home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / language / gfaxpert.lzh / GFAXPERT.ASC < prev    next >
Text File  |  1987-04-22  |  225KB  |  5,736 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.                                 Your Second
  16.                                GFA-BASIC 3.0
  17.                                    Manual
  18.  
  19.  
  20.  
  21.                               Second Edition
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39.  
  40.                              (c)  Han Kempen
  41.                              Coevorden, 1990
  42.  
  43.  
  44.  
  45.  
  46.  
  47.  
  48.  
  49.  
  50.  
  51.  
  52.                 Everything you always wanted to know about
  53.                   GFA-Basic 3.0, but were afraid to ask
  54.  
  55.                                    CONTENTS
  56.  
  57.           
  58. INTRODUCTION ..........................   7
  59.  
  60. 1. GENERAL 
  61. Start-up ..............................   9
  62. Application ...........................   9
  63. Monitor ...............................  10
  64. Break .................................  10
  65. Operating System ......................  10
  66.  
  67. 2. THE EDITOR 
  68. Abbreviated Commands ..................  12
  69. Syntax ................................  12
  70. Folded Procedures .....................  13
  71. Tab ...................................  13
  72. Cut and Paste .........................  13
  73. Load ..................................  13
  74. Save ..................................  14
  75. Llist .................................  14
  76. Insert-mode ...........................  15
  77. Direct mode ...........................  15
  78. DEFLIST ...............................  15
  79. Special Characters ....................  16
  80.  
  81. 3. VARIABLES 
  82. Variable Type .........................  17
  83. DEFWRD ................................  17
  84. Boolean ...............................  17
  85. Integer ...............................  18
  86. Floating Point ........................  18
  87. VAR ...................................  18
  88. FUNCTION ..............................  19
  89. CLEAR .................................  19
  90. ERASE .................................  19
  91. DUMP ..................................  19
  92. TYPE ..................................  20
  93. READ ..................................  20
  94. SWAP ..................................  20
  95. TIME$ .................................  21
  96. TIMER .................................  21
  97. DATE$ .................................  22
  98.  
  99. 4. MEMORY 
  100. RAM ...................................  23
  101. INT{} .................................  23
  102. RESERVE ...............................  23
  103. INLINE ................................  24
  104. MALLOC ................................  25
  105.  
  106. 5. SORT 
  107. QSORT v. SSORT ........................  26
  108. QSORT of number-arrays ................  26
  109. QSORT of string-arrays ................  26
  110.  
  111. 6. OPERATORS and NUMERICAL FUNCTIONS 
  112. \ .....................................  29
  113. PRED and SUCC .........................  29
  114. MOD ...................................  29
  115. BCLR ..................................  29
  116. BSET ..................................  30
  117. BCHG ..................................  30
  118. LOG ...................................  30
  119. SINQ and COSQ .........................  30
  120. EQV ...................................  31
  121. CARD and SWAP .........................  31
  122. MAX ...................................  31
  123. Correlation ...........................  31
  124.  
  125. 7. STRINGS 
  126. INSTR .................................  32
  127. LSET and RSET .........................  32
  128. Parser ................................  32
  129.  
  130. 8. KEYBOARD INPUT 
  131. INKEY$ ................................  33
  132. INPUT .................................  34
  133. INPUT$ ................................  35
  134. LINE INPUT ............................  35
  135. KEYTEST ...............................  35
  136. KEYGET ................................  35
  137. KEYLOOK ...............................  36
  138. KEYPRESS ..............................  37
  139. KEYDEF ................................  37
  140. Keyboard ..............................  37
  141. Keyclick, Keyrepeat and CapsLock ......  38
  142.   
  143. 9. SCREEN OUTPUT
  144. PRINT .................................  40
  145. LOCATE ................................  41
  146. PRINT TAB .............................  42
  147. Setscreen (XBIOS 5) ...................  42
  148. Font ..................................  43
  149.   
  150. 10. PRINTER 
  151. Printer ready .........................  45
  152. HARDCOPY ..............................  45
  153. Printer-commands ......................  47
  154.  
  155. 11. FILES
  156. Floppy Write Test .....................  50
  157. Step Rate .............................  50
  158. RAM-disk ..............................  50
  159. DIR$() ................................  50
  160. DIR and FILES .........................  51
  161. FSFIRST and FSNEXT ....................  52
  162. EXIST .................................  54
  163. LOF ...................................  54
  164. TOUCH .................................  54
  165. NAME ..................................  54
  166. KILL ..................................  54
  167. File Copy .............................  55
  168. Disk Format ...........................  55
  169. File Allocation Table (FAT) ...........  58
  170. Sectors ...............................  59
  171. Bootsector ............................  61
  172. BLOAD .................................  61
  173. INP and OUT ...........................  62
  174. INPUT and LINE INPUT ..................  62
  175. STORE and RECALL ......................  62
  176. FILESELECT ............................  63
  177.  
  178. 12. MIDI 
  179. INPMID$ ...............................  67
  180. INP ...................................  67
  181. Midi-commands .........................  67
  182.  
  183. 13. MODEM
  184. INPAUX$ ...............................  70
  185. INP ...................................  70
  186. Rsconf (XBIOS 15)......................  70
  187.  
  188. 14. MOUSE
  189. Editor ................................  71
  190. Fileselector ..........................  71
  191. MOUSE .................................  71
  192. SETMOUSE ..............................  71
  193. DEFMOUSE ..............................  72
  194.   
  195. 15. JOYSTICK
  196. STRIG and STICK .......................  74
  197.   
  198. 16. SOUND
  199. SOUND and WAVE ........................  75
  200. Dosound (XBIOS 32) ....................  75
  201. Samples ...............................  76
  202. Speech ................................  77
  203. Soundmachine ..........................  77
  204.  
  205. 17. PROGRAM DECISIONS 
  206. IF ... ENDIF ..........................  78
  207. SELECT ................................  78
  208.  
  209. 18. PROGRAM LOOPS
  210. Calculations ..........................  79
  211. FOR ... NEXT ..........................  79
  212. Loops .................................  80
  213.  
  214. 19. PROGRAM CONTROL 
  215. GOSUB .................................  82
  216. ON BREAK GOSUB ........................  82
  217. ERROR .................................  82
  218. EVERY and AFTER .......................  82
  219. GOTO ..................................  82
  220. DELAY .................................  83
  221. CHAIN .................................  83
  222. EXEC ..................................  83
  223.   
  224. 20. GRAPHICS
  225. SETCOLOR and VSETCOLOR ................  84
  226. Palette ...............................  84
  227. DEFMARK ...............................  87
  228. DEFFILL ...............................  87
  229. DEFLINE ...............................  89
  230. DEFTEXT ...............................  89
  231. GRAPHMODE .............................  90
  232. PLOT and DRAW .........................  91
  233. PCIRCLE ...............................  92
  234. CURVE .................................  92
  235. TEXT ..................................  92
  236. SPRITE ................................  93
  237. VQT_EXTENT ............................  95
  238. Line-A ................................  95
  239. HLINE .................................  96
  240. ACHAR and ATEXT .......................  96
  241. GET and PUT ...........................  96
  242. Degas-Pictures ........................  97
  243. Neochrome-Pictures ....................  98
  244. VSYNC .................................  98
  245. Scroll ................................  98
  246. ACLIP .................................  99
  247. Blitter ...............................  99
  248.  
  249. 21. EVENTS 
  250. MENU() ................................ 101
  251. ON MENU BUTTON ........................ 101
  252. ON MENU IBOX .......................... 102 
  253.  
  254. 22. PULLDOWN MENU
  255. OPENW 0 ............................... 103
  256. Desk-submenu .......................... 103
  257. File-submenu .......................... 103
  258.  
  259. 23. WINDOWS 
  260. GFA-windows ........................... 104
  261. CLOSEW ................................ 104
  262. TITLEW ................................ 105
  263. CLEARW ................................ 105
  264.  
  265. 24. AES-LIBRARY
  266. ALERT ................................. 106
  267. SHEL_GET and SHEL_PUT ................. 106
  268.  
  269. 25. GFAXPERT-FILES  
  270. GFAXPERT.DOC .......................... 108
  271. GFAXPERT.LIB .......................... 108
  272. INLINE ................................ 108
  273. STANxxxx.LST .......................... 108
  274. START ................................. 112
  275. small print ........................... 113
  276.  
  277. EPILOGUE .............................. 114
  278.  
  279. INDEX ................................. 115
  280.  
  281.  
  282.                                INTRODUCTION
  283.  
  284.  
  285. Right now you are reading the second edition of the text GFAXPERT.DOC. 
  286. This text is not meant to be a replacement of your GFA-manual. On the 
  287. contrary, I assume you are already familiar with the GFA-manual and now 
  288. want to know everything about GFA-Basic 3.0 that is not described properly 
  289. in the manual.
  290.  
  291. This text is about the (hidden) power of GFA-Basic 3.0. You will find 
  292. nothing about version 3.5, apart from this sentence. And this sentence, 
  293. because I would like to mention that I don't understand why GFA launched 
  294. version 3.5. GFA-Basic is becoming far too expensive.
  295.  
  296. All remarks in this text, especially about bugs, are based on GFA-Basic 
  297. 3.07. I still hope version 3.08 will become available (how naive...), 
  298. otherwise I'll have to wait for version 4. Not version 4.00 of course, 
  299. because I know there will be at least 200 bugs in the first release.
  300.  
  301. I wrote this text because I was disappointed by the contents of most books 
  302. about GFA-Basic 3.0. Some authors use page after page to describe a boring 
  303. program. Others delve deeply into menu's, windows and RSC, but ignore the 
  304. "regular" Basic-commands. Instead of complaining, I decided to write the 
  305. book that I would really like to see myself. Here it is. Forget all other 
  306. books about GFA-Basic, you need only two things: your GFA-manual and this 
  307. text. And to be honest, perhaps a good book about the AES-library, because 
  308. you won't find much about that subject in this text.
  309.  
  310. In this text you will find quite a few Procedures. Most Procedures that 
  311. are listed (or mentioned) in this text can be found in one of the LST-
  312. files in the folder GFAXPERT.LIB. Downloaders should look for the file 
  313. GFAXPRT2.ARC.
  314.  
  315. I strongly advise you to read the chapter 'GFAXPERT-FILES' thoroughly, 
  316. before you try to use the Procedure-library GFAXPERT.LIB. Especially note 
  317. the following :
  318.      (1) word-variables are the default
  319.      (2) a couple of variables are declared as Standard Globals
  320.      (3) some Standard Functions are defined
  321.      (4) a few Standard Procedures are present
  322.      (5) the Standard Array color.index() is declared
  323. A Procedure could use any of the Standard Globals, Functions, Procedures 
  324. or the Standard Array. I usually mention this in comment-lines in the 
  325. Procedure. If you Merge such a Procedure into an existing program, you 
  326. will have to adapt your program or the Procedure.
  327.  
  328. I still believe in GFA-Basic 3.0. And I also believe in sharing ideas, 
  329. Procedures and programs with other users, starting with you. If you feel 
  330. guilty about receiving all these goodies for (almost) nothing, you will 
  331. find a free consult in the chapter 'EPILOGUE'.
  332.  
  333. I could only write this text because many GFA-users shared their 
  334. experience with others. I dedicate this text to them. Special thanks to 
  335. everyone who pointed out bugs, mistakes and omissions in the first edition 
  336. of GFAXPERT.DOC. All mistakes in the second edition are made by
  337.  
  338.  
  339. Han Kempen
  340.  
  341.  
  342.                                1.  GENERAL
  343.  
  344.  
  345. Start-up
  346.  
  347. Programs in an AUTO-folder are executed automatically after a reset. The 
  348. interpreter GFABASIC.PRG is a GEM-program, and cannot be started in this 
  349. way. With TOS 1.4 you can install a GEM-program as auto-booting. With 
  350. older TOS-versions you could use a program like HEADSTRT.PRG in your AUTO-
  351. folder to start GFABASIC.PRG automatically. You can't start a GFA-program 
  352. this way (I think).
  353.  
  354. If you have written a (compiled) program that can be run either from the 
  355. AUTO-folder or from the desktop, you can determine which is the case :
  356.      IF PEEK(&H2C+4)=0        ! 4th byte of Line-F vector
  357.        (...)                  ! AUTO
  358.      ELSE
  359.        (...)                  ! desktop
  360.      ENDIF
  361.  
  362. There are several ways to (re)start your computer. The obvious one is to 
  363. switch the ST off, wait a few seconds (15 seconds with a 1040 ST!), and 
  364. switch on again. This is called a "cold" or "hard" reset. Your computer 
  365. suffers a little, and it takes some time. If you use the reset-button on 
  366. your ST, you perform a "warm" or "soft" reset. The operating system 
  367. automatically performs a warm reset if you switch between Low and Medium 
  368. resolution on the desktop. If you suspect a program of changing system 
  369. variables, you should always use a cold reset. After a warm reset the 
  370. system variables in low memory are not initialised again. Garbage will 
  371. stay there and will undoubtedly lead to interesting effects. You can 
  372. perform both a warm and a cold reset from GFA-Basic with the following 
  373. Procedures :
  374.      PROCEDURE coldstart
  375.        SLPOKE &H420,0
  376.        SLPOKE &H426,0         ! probably not necessary
  377.        SLPOKE &H43A,0
  378.        ~XBIOS(38,L:LPEEK(4))
  379.      RETURN
  380.      '
  381.      PROCEDURE warmstart
  382.        ~XBIOS(38,L:LPEEK(4))
  383.      RETURN
  384.  
  385. If you would like to boot from your second (external) drive B, try :
  386.      SLPOKE &H446,1      ! boot from drive B after next reset
  387.      @warmstart
  388.  
  389.  
  390. Application
  391.  
  392. It is convenient to install the extension GFA as an application for 
  393. GFABASIC.PRG. Click once on GFABASIC.PRG and choose Install Application 
  394. from the Options-menu. Type GFA as Document Type, click on OK and save the 
  395. desktop. If you double-click a GFA-program (extension .GFA) from the 
  396. desktop, GFABASIC.PRG is automatically loaded first. Choosing Install 
  397. Application you will only see the most recently installed application. Use 
  398. a disk-editor to examine the file DESKTOP.INF and you will find all 
  399. installed applications (look for #G). You could also use the method 
  400. described in the paragraph 'SHEL_GET and SHEL_PUT', or the RECALL-method 
  401. from the paragraph 'STORE and RECALL'.
  402.  
  403.  
  404. Monitor
  405.  
  406. The Atari colour monitor SC1224 works with a vertical frequency of either 
  407. 50 Hz or 60 Hz :
  408.      SPOKE &HFF820A,254       ! 50 Hz
  409.      SPOKE &HFF820A,252       ! 60 Hz
  410. For 60 Hz, bit 1 of the Sync Mode Register is cleared. Don't change bit 0, 
  411. or the video controller chip will not use the so-called sync pulses. After 
  412. a reset, the operating system defaults to 50 Hz. The screen is a little 
  413. larger than at 60 Hz, but the screen flickers slightly. If you connect 
  414. your ST to a TV through a modulator, you should use 50 Hz. Otherwise you 
  415. are advised to use 60 Hz.
  416.  
  417.  
  418. Break
  419.  
  420. It's not easy to find in the GFA-manual: you can stop a running program by 
  421. pressing <Control> <Left Shift> <Alternate> simultaneously. But if you're 
  422. reading this text, you know this already. It's impossible to interrupt a 
  423. program during DELAY! Study the Standard Procedure Break in one of the 
  424. STANxxxx.LST-files to see how I react after a 'Break'.
  425.  
  426.  
  427. Operating System
  428.  
  429. If you program in a language like GFA-Basic, you won't notice much of the 
  430. actual workhorse inside your ST-computer: The Operating System (TOS). But 
  431. even GFA-Basic does not have a Basic equivalent for all TOS-functions, 
  432. although you can use almost all functions from GFA-Basic.
  433.  
  434. TOS can be divided in two main parts: (GEM)DOS and GEM. The first is a 
  435. collection of "lower level" routines for communication with keyboard, 
  436. screen, printer, etc. In GFA-Basic you can call these routines with the 
  437. commands BIOS, XBIOS and GEMDOS. The Graphics Environment Manager (GEM) 
  438. consists of two collections of routines: the VDI (Virtual Device 
  439. Interface) and the AES (Application Environment Services). The VDI takes 
  440. care of regular graphics and should have included GDOS. Atari didn't 
  441. include GDOS in the VDI, so you have to load it if you need it. Most VDI-
  442. functions have a Basic equivalent in GFA. The AES takes care of the 
  443. communication with the user through menu, Alert-box, window, etc. Most 
  444. AES-functions can be accessed through the AES-library in GFA-Basic 3.0.
  445.  
  446. With GEMDOS-function 48 (Sversion) you can find the version of your 
  447. GEMDOS. For both the old TOS and the Blitter-TOS &H1300 (version 0.19) is 
  448. returned. The French Turbo-DOS has version 0.20 and the new Rainbow TOS of 
  449. 1988 has version 0.21.
  450. Another way to find out the version of TOS uses the system header of TOS 
  451. (not necessarily located in ROM!) :
  452.      adr%=LPEEK(&H4F2)
  453.      version$=HEX$(DPEEK(adr%+2))
  454. The good old ROM-TOS (1986, actually not so good) has version &H0100 
  455. (1.0), the Mega-ST Blitter-TOS (1987) version &H0102 (1.2). And of course 
  456. the new TOS ('Rainbow TOS') has version 1.4. You could also examine the 
  457. date of your TOS-version :
  458.      date$=HEX$(LPEEK(adr%+24))
  459. My ancient TOS 1.0 has '11201985' as the date.
  460.  
  461.  
  462.                               2.  THE EDITOR
  463.  
  464.  
  465. Abbreviated Commands 
  466.  
  467. The editor recognizes the following abbreviations (not a complete list) :
  468.  
  469. ALINE     - ALI          FILESELECT- FILE         POLYMARK  - POLYM
  470. ARECT     - AR           FILL      - FI           PRINT     - P or ?
  471. ARRAYFILL - ARR          FUNCTION  - FU           PROCEDURE - PRO
  472. ATEXT     - AT           GOSUB     - G or @       PSET      - PS
  473. BMOVE     - B            GRAPHMODE - GRA          QUIT      - Q
  474. BOUNDARY  - BOU          HIDEM     - HI           REPEAT    - REP
  475. CASE      - CA           HLINE     - HL           RESTORE   - RES
  476. CIRCLE    - CI           IF        - I            RETURN    - RET
  477. CLOSE     - CL           INPUT     - INP          RSET      - RS
  478. COLOR     - C            LINE      - LI           SELECT    - S
  479. DATA      - D            LINE INPUT- LI           SETCOLOR  - SET
  480. DEFFILL   - DEFF         LOCAL     - LOC          SETMOUSE  - SETM
  481. DEFLINE   - DE           LOOP      - L            SGET      - SG
  482. DEFMARK   - DEFMA        LPRINT    - LPR          SHOWM     - SH
  483. DEFMOUSE  - DEFM         LSET      - LS           SWAP      - SW
  484. DEFTEXT   - DEFT         MID$(..)= - MI ..)=      TEXT      - T
  485. DELETE    - DEL          MOUSE     - MOU          UNTIL     - U
  486. DRAW      - DR           NEXT      - N            VOID      - V
  487. EDIT      - ED           OPEN      - O            VSYNC     - VS
  488. ELLIPSE   - ELL          PAUSE     - PA           WAVE      - WA
  489. ELSE      - E            PBOX      - PB           WEND      - WE
  490. ENDFUNC   - ENDF         PCIRCLE   - PC           WHILE     - W
  491. ENDIF     - EN           PELLIPSE  - PE           
  492. ENDSELECT - ENDS         PLOT      - PL           
  493. ERASE     - ERA          POLYFILL  - POLYF        
  494. EXIT IF   - EX           POLYLINE  - POL          
  495.  
  496. If the abbreviated command is followed by anything else, you have to 
  497. insert a space (e.g. 'C 1'), except with '@' and '?' :
  498.      @proc1
  499.      G proc1
  500.      '
  501.      ?"hello"
  502.      P "hello"
  503.  
  504.  
  505. Syntax 
  506.  
  507. The parser checks for correct syntax after you press <Return>. Many typo-
  508. bugs are prevented this way. The only disadvantage is that the parser 
  509. recognizes some variables as commands. It's impossible to use the follo-
  510. wing names as the first word on a line: data_byte|, dirty$, double, 
  511. printer$, file%, quit!. The last one is nasty, because the parser changes 
  512. the line 'quit!=FALSE' into 'QUIT!=FALSE' without warning for a syntax-
  513. error. If you now run the program you will return to the desktop when QUIT 
  514. is encountered. Of course you have not lost your valuable program, because 
  515. you always Save before you Run. Do you really? If the parser refuses the 
  516. name of a variable, you can use LET (e.g. 'LET quit!=FALSE'). But you will 
  517. have to change the name if it is a label (e.g. the label 'data1:' could be 
  518. changed into '1data:' or 'd.ata1:').
  519.  
  520.  
  521. Folded Procedures 
  522.  
  523. If you press <Control> <Help> on a Procedure-line, all Procedures follo-
  524. wing and including the current one are folded/unfolded. You can unfold all 
  525. Procedures at once by putting the cursor on the first Procedure-line and 
  526. pressing <Control> <Help>. I suggest you leave all Procedures in the 
  527. Procedure-Library GFAXPERT.LIB folded, unless you want to examine a 
  528. Procedure. The editor-commands 'Find' and 'Replace' will skip folded 
  529. Procedures. Never change the Procedure-line of a folded Procedure, always 
  530. unfold it first.
  531.  
  532.  
  533. Tab 
  534.  
  535. If you press <Tab>, the cursor jumps to the next tab-position, without 
  536. altering the current line. If you use <Left Shift> <Tab>, the line is 
  537. filled with spaces from the current cursor-position to the next tab-
  538. position. Pressing <Right Shift> <Tab> erases all consecutive spaces to 
  539. the left of the current cursor-postition. If the current cursor-position 
  540. happens to be a space, this space and all spaces to the right are erased 
  541. as well.
  542.  
  543.  
  544. Cut and Paste 
  545.  
  546. If you press <Control> <P>, the current line from the cursor to the end of 
  547. the line is cut, and saved in an internal buffer. <Control> <O> inserts  
  548. the saved line at the current cursor-position. You can use this method to 
  549. "cut and paste" a part of a line. Press <Control> <P>, then <Control> <O> 
  550. to restore the original line. Move the cursor to the desired position and 
  551. press <Control> <O>. Block-operations are only possible with complete 
  552. lines.
  553.  
  554.  
  555. Load 
  556.  
  557. You can use Load only with *.GFA-files, not with ASCII-files (such as the 
  558. *.LST-files). ST-Basic files are ASCII-files, so you can Merge them. 
  559.  
  560. More recent programs in GFA-Basic (from 3.04) cannot be loaded by earlier 
  561. interpreters (up to 3.02). Of course you should have the most current 
  562. version (at least version 3.07), but the following method should always 
  563. work. Lengthen the program until you can load it successfully :
  564.      OPEN "A",#1,file$
  565.      PRINT #1,STRING$(1000,0)
  566.      CLOSE #1
  567.  
  568.  
  569. Save
  570.  
  571. After 'Save' (*.GFA-file) or 'Save,A' (*.LST-file) with an existing file, 
  572. the old file is renamed with a BAK-extension. Nice precaution, but you 
  573. should delete those *.BAK-files every now and then. 
  574.  
  575. If you kill and save files regularly, new files will be stored in a 
  576. fragmented way. Loading a fragmented file takes more time than loading a 
  577. file that occupies consecutive sectors on the disk. You can correct this 
  578. as follows. First make a backup-disk (yes, you should already have one). 
  579. Copy all files to a RAM-disk by clicking on the drive-icon and dragging it 
  580. to the window of the destination drive. You can't use disk-copy (dragging 
  581. drive-icon to drive-icon) because the destination-drive is a RAM-disk. 
  582. Format the source-disk and copy all files back (this must be a file-copy, 
  583. not a disk-copy). Now, all files are saved on consecutive sectors. You 
  584. could speed up things a little bit more by copying the most-used files 
  585. first. The drive-head now needs less time to reach these files.
  586.  
  587. Don't try to 'Save,A' an existing file to a full disk. I have tried it 
  588. once and lost both the original file (should have become a *.BAK-file) and 
  589. of course the saved file. Also, the editor (or TOS) had erased the program 
  590. from memory... Thank you.
  591.  
  592.  
  593. Llist
  594.  
  595. There has been some confusion about the following point-commands for the 
  596. printer :
  597.      .p-       - point-commands are not printed
  598.      .p+       - point-commands are printed again
  599.      .llxx     - line-width
  600.      .plxx     - page-length
  601.      .pa       - form feed
  602. Sometimes the commands '.cp' and '.nu' are mentioned, but I don't know how 
  603. to use these. 
  604.  
  605. You can only use one point-command in one line. I use the following lines 
  606. for my printer (96 characters/line in Elite-mode) :
  607.      .p-
  608.      .n4
  609.      .lr3
  610.      .ll88
  611. Save this as LLIST.LST and Merge it after the last line of a program 
  612. before choosing 'Llist'. The actual listing is then printed with 80 
  613. characters/line, preceded by the line-numbers (4 characters + space). If 
  614. your program is longer than 10000 lines, you should use '.n5', but in that 
  615. case you probably don't have time to read this. A nice touch is the 
  616. automatic execution of a form feed after printing the listing.
  617.  
  618. If the listing contains special characters (ASCII-code < 32 or > 126), 
  619. some of those characters might be interpreted as printer-commands. My 
  620. printer switches to condensed printing after receiving the Atari-symbol. 
  621. Installing the proper printer-driver (e.g. PTEPSON.PRG) will prevent that. 
  622. But I never install a printer-driver because there are some serious 
  623. disadvantages. Read more about it in the paragraph 'HARDCOPY'.
  624.  
  625. You can stop the printing process by pressing the 'Break'-combination 
  626. <Control> <Left Shift> <Alternate>, unless Break has been disabled with 
  627. 'ON BREAK CONT'. Your printer will continue printing though, until its 
  628. input-buffer is empty, or until you turn the printer off. 
  629.  
  630.  
  631. Insert-mode
  632.  
  633. If you return to the editor, you'll always be in Insert-mode, even if you 
  634. left the editor in Overwrite-mode. By the way, the editor restores the 
  635. original colour-palette, so you are not bothered by palette-changes in a 
  636. program. In the old days I was sometimes caught by the dreaded phenomenon 
  637. of black characters on a black background, but now you can always read the 
  638. listing on your screen. 
  639.  
  640. By the second way, there is only one thing I don't like about the GFA-
  641. editor. It's not easy to merge a Procedure from a LST-file with the 
  642. program you're working on. Save the program, clear memory with 'New', 
  643. 'Merge' the LST-file, mark the Procedure as a block, save the block, 
  644. 'Load' the original program, find the correct line and 'Merge' the saved 
  645. block. A new command NMerge (New+Merge) would make the life of a GFA-
  646. programmer a little easier. A better idea would be the command BMerge 
  647. (Block-Merge). Then I could choose this command, clip a Procedure-block, 
  648. and the block would be inserted in the listing automatically. Are you 
  649. reading this, Frank? If you are, how about a function for changing upper 
  650. case into lower case. In the GFA-EDITOR I SOMETIMES (oops) forget I 
  651. pressed CapsLock. And how about a function to clear a line from the cursor 
  652. to the next space-character. And...
  653.  
  654.  
  655. Direct Mode
  656.  
  657. Enter the Direct Mode by pressing <Esc> or <Shift> <F9> in the editor.
  658.  
  659. In Direct Mode you can restore the previously used line with <Undo>. With 
  660. <Up arrow> and <Down arrow> you can even recall up to 8 of the last used 
  661. lines. Press <Insert> to switch between Insert-mode and Overwrite-mode. As 
  662. usual <Esc> clears the line, but if you press <Esc> on an empty line, you 
  663. will return to the editor immediately. You can also return to the editor 
  664. with <Control> <Shift> <Alternate>, even without first clearing the 
  665. command-line. You can call Procedures in your program from the Direct Mode 
  666. (e.g. '@show'). If you (temporarily) merge some special Procedures with 
  667. the program you are developing, you could use the Direct Mode as a Command 
  668. Line Interpreter.
  669.  
  670.  
  671. DEFLIST
  672.  
  673. The command 'DEFLIST n' only works in Direct Mode, not in a program. You 
  674. can also choose 'Deflist' from the drop-down menu, after clicking on the 
  675. Atari-symbol.
  676. Special Characters
  677.  
  678. You can enter characters with ASCII-code 32-126 directly from the key-
  679. board. These characters are usually called ASCII-characters. The codes
  680. 0-31 and 127 are used as control-codes, but additionally special charac-
  681. ters have been assigned to these codes. The characters with code 128-255 
  682. are sometimes called "extended ASCII-characters" and are partly identical 
  683. to the IBM-characters with the same codes. I loosely use the expression 
  684. "ASCII-code" for all codes 0-255.
  685.  
  686. You can enter characters with code 0-31 or 127-255 by pressing <Alternate> 
  687. and then entering the character code. Release the <Alternate>-key and the 
  688. character appears on your screen. E.g., you could enter the Escape-
  689. character by holding <Alternate> down and pressing <2> and <7>. This is 
  690. much faster than entering CHR$(27), but Llisting a file with Escape-
  691. characters is probably not a good idea (less important, 1st Word Plus 
  692. could get confused too). Llisting CHR$(27) doesn't bother your printer at 
  693. all. It's not possible to enter CHR$(10) or CHR$(13) with the 'Alternate'-
  694. way. You can enter the first by pressing <Control> <A> and then <1> <0> 
  695. <Return>. For code 13 you have to use CHR$(13).
  696.  
  697. Never use code 4 (EOT, visible as left arrow) in a LST-file. If you Merge 
  698. a LST-file, the GFA-editor thinks the end of the file is reached at that 
  699. point (&H04) and refuses to load anything following this code!
  700.  
  701.  
  702.                               3.  VARIABLES
  703.  
  704.  
  705. Variable-type
  706.  
  707. In GFA-Basic we use the expressions 'Byte', 'Word' and 'Integer' for the 
  708. three integer-variables. Because all three are integers, the expression 
  709. 'Integer' for the 4-byte integer-variable is sligthly confusing. In other 
  710. languages this variable is called 'Longword' or simply 'Long'. An address 
  711. in RAM should always be a 4-byte integer.
  712.  
  713.  
  714. DEFWRD
  715.  
  716. I prefer to declare word-variables as the default (for variables without 
  717. postfix) with: DEFWRD "a-z"
  718.  
  719. I recommend the use of word-variables (2 bytes) for two reasons. In 
  720. calculations, the use of the special integer-operators (ADD, SUB, INC, 
  721. etc.) speeds the program up considerably. If you insist on using the 
  722. regular operators (+, -, etc.) you should use floating point variables 
  723. instead. Using the regular operators, the interpreter has to convert 
  724. integer-variables to floating point, does the calculation and converts the 
  725. result back to integer again. That's why a#*b# is calculated faster than 
  726. a&*b&. But MUL(a&,b&) is much faster than a#*b#. It takes some time to 
  727. recognize what an expression like DIV(a,MUL(ADD(a,b),SUB(b,c))) means. I 
  728. suggest you use the regular operators if the calculation-time is not 
  729. critical. In loops, the gain in calculation time really counts, so you 
  730. should use the integer-operators. That way you will learn Polish too. The 
  731. second reason for using word-variables is, that in a compiled program 
  732. calculations with word-integers are usually the fastest.
  733.  
  734. IMPORTANT: if a number-variable has no postfix in this text, you should 
  735. assume it's a word-variable. I'll use the postfix |, % or # where 
  736. appropriate. Please note that the interpreter assumes a number-variable 
  737. without postfix is a floating point variable, unless you use DEFWRD "a-z".
  738.  
  739.  
  740. Boolean
  741.  
  742. The following five lines :
  743.      IF number>0
  744.        test!=TRUE
  745.      ELSE
  746.        test!=FALSE
  747.      ENDIF
  748. can be shortened to just one line :
  749.      test!=(number>0)
  750. This works, because the '>'-operator returns TRUE or FALSE (actually -1
  751. or 0). 
  752.  
  753. Another little trick :
  754.      IF i=1
  755.        n=n*2
  756.      ELSE IF i=2
  757.        n=n*5
  758.      ELSE
  759.        n=0
  760.      ENDIF
  761. This could be shortened to :
  762.      n = n*-2*(i=1) + n*-5*(i=2)
  763. The example is ridiculous, but the principle involved could be useful. The 
  764. expressions 'i=1' and 'i=2' are either 0 (FALSE) or -1 (TRUE).
  765.  
  766. It is not necessary to use something like :
  767.      IF flag!=TRUE
  768.        (...)
  769.      ENDIF
  770. You can simply use :
  771.      IF flag!
  772.        (...)
  773.      ENDIF
  774.  
  775.  
  776. Integer
  777.  
  778. You can't assign 2^31 to a 4-byte integer-variable. Although an integer 
  779. contains 32 bits, you can't use bit 31. This bit is a flag for a negative 
  780. integer. The largest positive number you can assign to an integer-variable 
  781. is therefore 2^31-1 (2147483647). I could have written an analogue 
  782. paragraph about the 2-byte word-variables, but I didn't. 
  783.  
  784.  
  785. Floating Point
  786.  
  787. The range of floating point variables (postfix #) is :
  788.      -1.0E1000 < x# < 1.0E1000
  789. Larger or smaller numbers can be used in calculations, but not printed, 
  790. because the exponent may contain not more than 3 digits (1.0E1000 is 
  791. displayed as 1.0E;00).
  792.  
  793.  
  794. VAR
  795.  
  796. If you call a Procedure and use VAR (call by reference), all variables 
  797. and/or arrays after VAR are called by reference. An example to clarify 
  798. this :
  799.      @test(10,5,number%,array%())
  800.      (...)
  801.      PROCEDURE test(a,b,VAR x%,y%())
  802.        ' now a=10 and b=5 (call by value)
  803.        ' number% and array%() can now be used as x% and y%()
  804.        x%=a+b                 ! global variable number% is now 15
  805.        ARRAYFILL y%(),1       ! all elements of array%() are now 1
  806.      RETURN
  807. In prehistoric days you could have used SWAP, but VAR makes life easier :
  808.      @test(*a%())
  809.      (...)
  810.      PROCEDURE test(ptr%)
  811.        SWAP *ptr%,x%()        ! array a%() temporarily renamed as x%()
  812.        (...)                  ! do something with the array
  813.        SWAP *ptr%,x%()        ! restore pointer before leaving Procedure
  814.      RETURN
  815.  
  816.  
  817. FUNCTION
  818.  
  819. You can only leave a FUNCTION by RETURNing a value or a string. This 
  820. value/string is usually assigned to a variable. If the FUNCTION returns a 
  821. string, the function-name has to end with '$' :
  822.      FUNCTION test
  823.        RETURN 126
  824.      ENDFUNC
  825.      '
  826.      FUNCTION test$
  827.        RETURN "this is a string"
  828.      ENDFUNC
  829.  
  830.  
  831. CLEAR
  832.  
  833. Because CLEAR is automatically executed when you run a program, it's not 
  834. necessary to start you program with this command.
  835.  
  836.  
  837. ERASE
  838.  
  839. It's impossible to reDIMension an existing array. You first have to ERASE 
  840. the existing array and then you can DIMension a new array. It is not 
  841. necessary to test for the existence of an array with DIM?() before you use 
  842. ERASE. In other words, you can use ERASE even if the array doesn't exist :
  843.      ERASE array$()      ! just in case this array already exists 
  844.      DIM array$(200)     
  845.  
  846. After ERASEing an array, GFA rearranges the remaining arrays. All arrays 
  847. that have been DIMensioned after the deleted array are moved in order to 
  848. fill the gap of the deleted array. This is important if you use V:array(0) 
  849. in your program (read the paragraph 'RESERVE').
  850.  
  851.  
  852. DUMP
  853.  
  854. Examine all variables in your program by typing 'DUMP' in Direct Mode. 
  855. Press <CapsLock> to slow down the scrolling-speed, or press the right 
  856. <Shift>-key to temporarily stop the scrolling. The Procedure Debug enables 
  857. you to use DUMP during debugging. This is the best way to discover those 
  858. nasty typo-bugs in a variable-name. You'll probably be surprised to see 
  859. the names of deleted variables as well. Also, any variable-name you used 
  860. in Direct Mode appears. All these names are SAVEd with the program! Delete 
  861. all unwanted names as follows (a RAM-disk would be convenient) :
  862.      - Load the file
  863.      - Save,A (press <Return> in Fileselector)
  864.      - New
  865.      - Merge (press <Return> again)
  866.      - Save (press <Return> once more)
  867. The file could be much shorter after this operation.
  868.  
  869.  
  870. TYPE
  871.  
  872. The command TYPE does not seem to work properly if you use local 
  873. variables. I don't know what's wrong.
  874.  
  875.  
  876. READ
  877.  
  878. As a rule, I always RESTORE the appropriate label before READing DATA-
  879. lines. That way I can use DATA-lines in Procedures :
  880.      PROCEDURE read.data
  881.        RESTORE these.data
  882.        (...)                  ! READ the DATA here
  883.        these.data:
  884.        DATA 1,2,3,4
  885.      RETURN
  886.  
  887.  
  888. SWAP
  889.  
  890. The 52 cards in bridge (or another card-game) can be represented by a 
  891. byte-array. Fill the elements 1-52 of the array with the value 1-52. The 
  892. values 1-13 would represent the Club-cards (2,3,4,...,Q,K,A), values
  893. 14-26 the Diamonds, values 27-39 the Hearts and values 40-52 the Spades. 
  894. Shuffling the cards can now be simulated with the Procedure Shuffle :
  895.      DIM deck|(52)
  896.      FOR i=1 TO 52       ! ignore index 0
  897.        deck|(i)=i
  898.      NEXT i
  899.      @shuffle(deck|())
  900.      (...)
  901.      PROCEDURE shuffle(VAR proc|())
  902.        LOCAL i,j
  903.        FOR i=DIM?(proc|())-1 DOWNTO 2
  904.          j=RAND(i)+1
  905.          SWAP proc|(j),proc|(i)
  906.        NEXT i
  907.      RETURN
  908.  
  909.  
  910. TIME$
  911.  
  912. You can use TIME$ to print the current time on the screen. In the 
  913. Procedure Time you'll find a way to print the time every second, although 
  914. TIME$ is updated every two seconds :
  915.      PROCEDURE time
  916.        ' *** activate with : EVERY 200 GOSUB time
  917.        ' *** global :  TIMER$
  918.        LOCAL t$
  919.        t$=TIME$
  920.        IF t$=timer$
  921.          MID$(timer$,8)=SUCC(RIGHT$(timer$))
  922.        ELSE
  923.          timer$=t$
  924.        ENDIF
  925.        PRINT AT(1,1);timer$
  926.      RETURN
  927.  
  928.  
  929. TIMER
  930.  
  931. If you need a stopwatch, you can use the following Procedures :
  932.      PROCEDURE stopwatch
  933.        ' *** global :  STOP.SECONDS#  STOP.H  STOP.M  STOP.S  WATCH.ON!
  934.        LOCAL s#
  935.        IF watch.on!
  936.          stop.watch#=TIMER
  937.          stop.seconds#=(stop.watch#-start.watch#)/200
  938.          stop.h=stop.seconds#/3600
  939.          s#=stop.seconds#-stop.h*3600
  940.          stop.m=s#/60
  941.          stop.s=s#-stop.m*60
  942.          watch.on!=FALSE
  943.        ELSE
  944.          watch.on!=TRUE
  945.          start.watch#=TIMER
  946.        ENDIF
  947.      RETURN
  948.      ' 
  949.      PROCEDURE print.stopwatch
  950.        IF stop.h>0
  951.          PRINT stop.h;" h ";stop.m;" m";
  952.        ELSE
  953.          IF stop.m>0
  954.            PRINT stop.m;" m ";stop.s;" s";
  955.          ELSE
  956.            IF stop.seconds#>=10
  957.              PRINT USING "##.# s",stop.seconds#;
  958.            ELSE
  959.              PRINT USING "#.## s",stop.seconds#;
  960.            ENDIF
  961.          ENDIF
  962.        ENDIF
  963.      RETURN
  964. You start the stopwatch by calling the Procedure Stopwatch. Calling this 
  965. Procedure again will stop the stopwatch. Then you can PRINT the elapsed 
  966. time at the current cursor-position with the Procedure Print.stopwatch, or 
  967. you could use one of the Global Variables from the Procedure Stopwatch to 
  968. do something else.
  969.  
  970.  
  971. DATE$
  972.  
  973. Find the day of the week with the Procedure Day.of.week :
  974.      PROCEDURE day.of.week(day.date$,VAR day$)
  975.        LOCAL day,mp,month,year,m,h,w,week$,n
  976.        day=VAL(LEFT$(day.date$,2))
  977.        mp=INSTR(day.date$,".")
  978.        month=VAL(MID$(day.date$,mp+1,2))
  979.        year=VAL(RIGHT$(day.date$,4))
  980.        IF month<=2
  981.          m=10+month
  982.          year=year-1
  983.        ELSE
  984.          m=month-2
  985.        ENDIF
  986.        h=year/100
  987.        y=year-100*h
  988.        w=(TRUNC(2.6*m-0.2)+day+y+TRUNC(y/4)+TRUNC(h/4)-2*h) MOD 7
  989.        RESTORE weekdays
  990.        FOR n=0 TO w
  991.          READ day$
  992.        NEXT n
  993.        '
  994.        weekdays:
  995.        DATA Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday
  996.      RETURN
  997. This Procedure uses Zeller's Congruence to determine the day of the week.
  998.  
  999.  
  1000.                                 4.  MEMORY
  1001.  
  1002.  
  1003. RAM
  1004.  
  1005. An overview of the memory of my 1040 ST (start at the bottom) :
  1006.                      address
  1007.                     &H FFFFF   top of memory of 1040 ST (1024 K)
  1008.                     &H FFD00   767 unused (?) bytes 
  1009.        XBIOS(2)   = &H F8000   screen memory (32000 bytes)
  1010.        HIMEM      = &H F4000   16384 unused bytes (MALLOC(-1))
  1011.                     &H .....   free memory (length FRE(0) bytes)
  1012.                     &H 388EA   program + variables (length varies)
  1013.                     &H 10C2E   GFA-Basic 3.07 interpreter
  1014.        BASEPAGE   = &H 10B2E   Basepage GFA-Basic (256 bytes)
  1015.                     &H  A100   start of available RAM
  1016.                     &H  6100   global AES-variables
  1017.                     &H  29B4   global BIOS- and GEMDOS-variables
  1018.        L~A        = &H  293A   Line A variables
  1019.                     &H   93A   local BIOS-variables + BIOS-stack
  1020.                     &H   400   BIOS system-variables
  1021.                     &H     0   exception vectors
  1022.  
  1023. The BIOS system-variables (&H400 - &H4FF) are "cast in concrete" by Atari. 
  1024. Other (undocumented) variables in RAM should be avoided. 
  1025.  
  1026.  
  1027. INT{}
  1028.  
  1029. You can use either INT{adr%} or WORD{adr%}. As you know, w=WORD{adr%} is 
  1030. faster than w=DPEEK(adr%), but you can't use WORD{} and the other related 
  1031. commands in supervisor mode. This means you can't access memory below 
  1032. address &H800. Of course you can PEEK/DPEEK/LPEEK everywhere (DPEEK and 
  1033. LPEEK on even addresses only), and you can use SPOKE/SDPOKE/SLPOKE to 
  1034. write in supervisor mode. 
  1035.  
  1036.  
  1037. RESERVE
  1038.  
  1039. The command RESERVE can be used in three different ways :
  1040.      RESERVE  n% : reserve n% bytes for GFA-Basic, release RAM up to HIMEM
  1041.      RESERVE -n% : reserve last n% bytes of RAM up to HIMEM
  1042.      RESERVE     : restore to original
  1043. The second command is my favourite. You must use a multiple of 256 with 
  1044. RESERVE. After 'RESERVE -400', only 256 bytes are released to GEMDOS. In 
  1045. this case you would have to use 'RESERVE -512', although you need only 400 
  1046. bytes! Use the Function Multiple if arithmetic is not your strongest 
  1047. point :
  1048.      RESERVE -@multiple(n%,256)
  1049. Use 'RESERVE -n%' only once in your program. If you RESERVE memory a 
  1050. second time with 'RESERVE -m%', GFA releases m% bytes, not n%+m%.
  1051.  
  1052. The command RESERVE (restore) does not always function properly. Especial-
  1053. ly after EXEC 3 it's often impossible to restore the memory. I suspect 
  1054. this has something to do with the use of the malloc-function by the 
  1055. operating system. You could try the following :
  1056.      RESERVE -n%         ! reserve as much as needed (multiple of 256)
  1057.      base%=EXEC(3,...)   ! load, but don't start
  1058.      (...)
  1059.      ~MFREE(HIMEM)       ! memory above GFA-Basic
  1060.      ~MFREE(base%)       ! memory from Basepage of loaded program
  1061.      RESERVE             ! hope it works now
  1062. Don't be surprised by hang-ups or bombs after this operation...
  1063.  
  1064. There are several ways to reserve a part of memory for special purposes 
  1065. such as music, pictures or other programs. E.g., you could use a string-
  1066. variable to store a complete screen or a GET-picture. Don't use strings if 
  1067. garbage collection is a serious risk. If a large array is declared, the 
  1068. interpreter sometimes moves the strings in memory to create space for the 
  1069. new array. If you assign a new string to an existing string-variable, the 
  1070. old string is not erased. During garbage collection all unused strings are 
  1071. deleted and the active strings are rearranged. This means the address of a 
  1072. string (accessed through VARPTR or V:) is not fixed. That's not important 
  1073. for a GET-picture, because 'PUT x,y,pic$' still works all right. But if 
  1074. you swap screens with ~XBIOS(5,L:adr%,-1,-1), or call a routine with
  1075. ~C:adr%(...), garbage collection will be fatal. One solution is not to use 
  1076. a variable for the address, but to use VARPTR or V:. A different approach 
  1077. would be the use of a byte-array :
  1078.      OPEN "I",#1,file$
  1079.      LET bytes%=LOF(#1)            ! how much space is needed?
  1080.      CLOSE #1
  1081.      DIM assembler|(bytes%-1)      ! create space for assembler-routine
  1082.      adr%=V:assembler|(0)        
  1083.      BLOAD file$,adr%              ! load the routine
  1084. You can use the variable adr% safely, because a garbage collection has no 
  1085. influence on arrays. However, after ERASEing an array, all arrays that 
  1086. have been DIMensioned after the deleted array are moved in memory. So the 
  1087. array-method is not reliable either, unless you are certain that ERASE 
  1088. will not be used after you have determined the address of the byte-array. 
  1089. Another solution would be to declare the byte-array early in your program, 
  1090. so it will not be moved after ERASE. The only complete safe way is the use 
  1091. of INLINE or MALLOC. 
  1092.  
  1093.  
  1094. INLINE
  1095.  
  1096. Use D (=DUMP) to dump an Inline-file in Hex-code to the printer.
  1097.  
  1098. Don't use 'Save,A', because you will lose the Inline-code. You can't use 
  1099. INLINE in LST-files. If you would like to use INLINE in combination with a 
  1100. LST-file you could proceed as follows. First, create an INLINE-folder in 
  1101. the main directory and SAVE the Inline-code as a file (extension INL) in 
  1102. this folder. Merge the LST-file in your program and load the Inline-code 
  1103. in the INLINE-line. The program should be saved with 'Save'. 
  1104.  
  1105. The only limitation with INLINE is the maximum length of 32746 bytes. If 
  1106. you need more space, you have to use MALLOC. 
  1107.  
  1108. If you change the length of an existing INLINE-line, the editor sometimes 
  1109. erases a few lines from your program. It's safer to completely delete the 
  1110. old INLINE-line and then enter the new INLINE-line.
  1111.  
  1112.  
  1113. MALLOC
  1114.  
  1115. This is how you could use MALLOC :
  1116.      unused%=MALLOC(-1)  ! "unused" memory above HIMEM (used by GEM)
  1117.      RESERVE -n%         ! release last n% bytes to GEMDOS
  1118.      max%=MALLOC(-1)
  1119.      IF max%<>0
  1120.        adr%=MALLOC(max%-unused%)  ! n% bytes now available to GFA-Basic
  1121.      ELSE
  1122.        ' error
  1123.      ENDIF
  1124.      (...)               ! do something interesting
  1125.      ~MFREE(adr%)        ! give back to GEMDOS...
  1126.      RESERVE             ! and back to GFA-Basic
  1127. Atari recommends you leave at least 8K to GEM, so you can't go wrong if 
  1128. you leave 16384 bytes to GEM (see paragraph 'RAM').
  1129.  
  1130. Do not use MALLOC to allocate a lot of small memory-blocks, as GEMDOS will 
  1131. get confused. This problem is related to the "40-folder limit", because 
  1132. MALLOC uses the same buffer that is used to store information about a 
  1133. folder (see paragraph 'FILESELECT'). Allocate one large area and split it 
  1134. up in as many parts as you need. Also consider the use of INLINE, strings 
  1135. or byte-arrays instead of using MALLOC (read the paragraph 'RESERVE'). Do 
  1136. not use MALLOC in an accessory, or the allocated memory may be lost if the 
  1137. user changes the resolution.
  1138.  
  1139. MALLOC(-1) returns the size of the largest available memory-block. Expect 
  1140. problems if another program has allocated a couple of separate memory-
  1141. blocks to GEMDOS. In that case you would have to use MALLOC(-1) again, 
  1142. until a returned value of '0' indicates there are no more memory-blocks 
  1143. available.
  1144.  
  1145.  
  1146.                                  5.  SORT
  1147.  
  1148.  
  1149. QSORT v. SSORT
  1150.  
  1151. QSORT is faster than SSORT, unless the array is almost sorted already. I 
  1152. understand QSORT uses the recursive Quick-sort method, so you need more 
  1153. memory than with SSORT (iterative Shell-sort). Sort-freaks can study the 
  1154. Procedures Quick.sort.int and Shell.sort.int to see how the Quick-sort and 
  1155. Shell-sort can be implemented with ordinary GFA-Basic commands (like that 
  1156. dance: Quick, Shell, slow).
  1157.  
  1158.  
  1159. QSORT of number-arrays
  1160.  
  1161. Number-arrays can be QSORTed in three different ways :
  1162.      QSORT x%()          - sorts array ; also with x|(), x&() or x#()
  1163.      QSORT x%(),n        - sorts elements 0 through n-1
  1164.      QSORT x%(),n,y%()   - elements of y%() are swapped too
  1165. In all cases x%(-1) results in sorting in decreasing order.
  1166.  
  1167. The third method is interesting if you need a sorted output, but don't 
  1168. want to change the original array. You can accomplish this as follows :
  1169.      - copy x%() to temporary array temp%()
  1170.      - determine index of last element : last=DIM?(temp%())-1
  1171.      - create index array : DIM index%(last)
  1172.      - fill index-array with index 0 through last
  1173.      - sort array : QSORT temp%(),last+1,index%()
  1174.      - ERASE temp%()
  1175. The index-array must be an integer-array (postfix %). Also, the number of 
  1176. elements is not optional if you sort with an index-array. You can now 
  1177. print the numbers in array x%() in increasing order :
  1178.      FOR i=0 TO last
  1179.        PRINT x%(index%(i))
  1180.      NEXT i
  1181.  
  1182. I have never seen the correct syntax for QSORT in print, so here it is :
  1183.      QSORT x([s])[,n[,y%()]]
  1184.  
  1185.  
  1186. QSORT of string-arrays
  1187.  
  1188. A string-array can be sorted in the same three ways as described for 
  1189. number-arrays. If you have created an index-array with last_name$(), you 
  1190. could print an alphabetical list :
  1191.      FOR i=0 TO last
  1192.        PRINT first_name$(index%(i))'last_name$(index%(i))
  1193.      NEXT i     
  1194.  
  1195. There are two extra possibilities with string-arrays. 
  1196.  
  1197.  
  1198. For the first possibility, create a byte-array and fill with appropriate 
  1199. ASCII-values :
  1200.      DIM ascii|(255)
  1201.      ARRAYFILL ascii|(),32    ! CHR$(32) is the space-character
  1202.      FOR i=48 TO 57
  1203.        ascii|(i)=i            ! 0 - 9
  1204.      NEXT i
  1205.      FOR i=65 TO 90
  1206.        ascii|(i)=i            ! A - Z
  1207.      NEXT i
  1208.      FOR i=97 TO 122
  1209.        ascii|(i)=SUB(i,32)    ! a - z converted to A - Z
  1210.      NEXT i
  1211. All characters that are not numbers or letters will be treated as a space 
  1212. (ASCII-value 32). Use the array ascii|() for sorting a string-array :
  1213.      QSORT x$() WITH ascii|()
  1214. Now 'Atari' and 'ATARI' are treated exactly the same, because the 
  1215. interpreter uses the array ascii|() to convert lower case letters tempora-
  1216. rily to upper case before sorting. You can even treat the international 
  1217. characters (ASCII-values > 127) correctly, e.g. ascii|(129)=85. Use a few 
  1218. DATA-lines to add the correct ASCII-value, like this :
  1219.      DATA 128,67,129,85,130,69
  1220. You can combine this method with an index-array as well. The correct 
  1221. syntax is :
  1222.      QSORT x$([s]) WITH b|() [,n[y%()]]
  1223. If you have done your homework, you should now be able to write a clever 
  1224. alphabetical sorting-program yourself. You wanted to become an expert, 
  1225. didn't you? Compare your program with the Procedures Ascii.qsort and 
  1226. String.index.qsort :
  1227.      PROCEDURE ascii.qsort(VAR txt$())
  1228.        IF DIM?(ascii|())=0
  1229.          @initio.ascii.array
  1230.        ENDIF
  1231.        QSORT txt$() WITH ascii|()
  1232.      RETURN
  1233.      ' 
  1234.      PROCEDURE initio.ascii.array
  1235.        LOCAL i,code1,code2
  1236.        DIM ascii|(255)
  1237.        ARRAYFILL ascii(),32           ! fill with space-character
  1238.        FOR i=48 TO 57
  1239.          ascii|(i)=i                  ! 0 - 9
  1240.        NEXT i
  1241.        FOR i=65 TO 90
  1242.          ascii|(i)=i                  ! A - Z
  1243.        NEXT i
  1244.        FOR i=97 TO 122
  1245.          ascii|(i)=SUB(i,32)          ! a - z, converted to A - Z
  1246.        NEXT i
  1247.        RESTORE ascii.data
  1248.        REPEAT
  1249.          READ code1,code2
  1250.          ascii|(code1)=code2
  1251.        UNTIL code1=0
  1252.        '
  1253.        ascii.data:
  1254.        ' *** format : ASCII-code,replacement
  1255.        DATA 128,67,129,85,130,69,131,65,132,65,133,65,134,65,135,67
  1256.        DATA 136,69,137,69,138,69,139,73,140,73,141,73,142,65,143,65
  1257.        DATA 144,69,145,65,146,65,147,79,148,79,149,79,150,85,151,85
  1258.        DATA 152,121,153,79,154,85,155,67,158,83,160,65,161,73,162,79
  1259.        DATA 163,85,164,78,165,78,166,65,167,79,176,65,177,79,178,79
  1260.        DATA 179,79,180,79,181,79,182,65,183,65,184,79,192,121,193,121
  1261.        DATA 225,83,0,0
  1262.      RETURN
  1263.      '
  1264.      PROCEDURE string.index.qsort(switch!,VAR txt$(),index%())
  1265.        ' *** the index-array has to exist already 
  1266.        ' *** if switch!=TRUE, array ascii|() is used 
  1267.        LOCAL last,i
  1268.        last=DIM?(txt$())-1           ! index of last element
  1269.        DIM temp$(last)
  1270.        FOR i=0 TO last
  1271.          temp$(i)=txt$(i)
  1272.        NEXT i
  1273.        FOR i=0 TO last
  1274.          index%(i)=i
  1275.        NEXT i
  1276.        IF switch!
  1277.          IF DIM?(ascii|())=0
  1278.            @initio.ascii.array
  1279.          ENDIF
  1280.          QSORT temp$() WITH ascii|(),last+1,index%()
  1281.        ELSE
  1282.          QSORT temp$(),last+1,index%()
  1283.        ENDIF
  1284.        ERASE temp$()
  1285.      RETURN
  1286.  
  1287. The second extra possibility with string-arrays is the use of 'OFFSET o' 
  1288. to ignore the first 'o' characters during sorting. Suppose you have 
  1289. created an array files$() with FILES and would like to sort the files by 
  1290. length :
  1291.      QSORT files$() OFFSET 13,n
  1292. The first character (either a space or '*') and the filename (the next 12 
  1293. characters) are now ignored during sorting.
  1294.  
  1295.  
  1296.                   6.  OPERATORS and NUMERICAL FUNCTIONS
  1297.  
  1298.  
  1299. \
  1300.  
  1301. The operator '\' (backslash) is identical to DIV :
  1302.      a=b\c
  1303. Integer-division is not as useful as the other integer-operations, because 
  1304. the result is an integer. Of course it is, but this can easily result in 
  1305. large rounding errors.
  1306.  
  1307.  
  1308. PRED and SUCC
  1309.  
  1310. PRED(i) is faster than i-1 and SUCC(i) is faster than i+1. Both functions 
  1311. can also be used with strings. Note the clever use (ahem) of SUCC in the 
  1312. following line from the Procedure Time :
  1313.      MID$(timer$,8)=SUCC(RIGHT$(timer$))
  1314. The rightmost digit of timer$ (always even) is increased with one.
  1315.  
  1316.  
  1317. MOD
  1318.  
  1319. If you use a counter in a loop in order to do something every time the 
  1320. counter reaches a multiple of 10, you could do this as follows :
  1321.      IF counter MOD 10=0      ! multiple of 10?
  1322.        (...)                  ! yes, do something
  1323.      ENDIF
  1324. You could also use :
  1325.      IF MOD(counter,10)=0
  1326.        (...)
  1327.      ENDIF
  1328.  
  1329.  
  1330. BCLR
  1331.  
  1332. In GFA-Basic version 2.x you used AND to clear a bit :
  1333.      x|=x| AND &X11111011     ! clear bit 2 of this byte
  1334. Remember, the first (rightmost) bit is bit 0, so a byte contains bit 0-7 
  1335. from right to left. In GFA-Basic 3.0 you clear a bit simply with :
  1336.      x|=BCLR(x|,2)            ! clear bit 2 of this byte
  1337. But if you want to clear more than one bit, you should use the AND-method:
  1338.      x|=x| AND &X11110000     ! clear bit 0-3 of this byte
  1339. In this case you use a so-called mask to clear certain bits. You can use 
  1340. AND also as a function :
  1341.      y|=AND(x|,&X11110000)    ! even faster than previous example
  1342. This way you can test if a bit-mask "fits" a variable :
  1343.      IF AND(x|,mask|)
  1344.        (...)
  1345.      ENDIF
  1346. An example of this method :
  1347.      IF AND(BIOS(11,-1),&X1001)
  1348.        (...)             ! user pressed <Alternate> + right <Shift>
  1349.      ENDIF
  1350. BSET
  1351.  
  1352. In GFA-Basic 2.x you needed OR to set a bit, but now you use BSET :
  1353.      x|=BSET(x|,1)
  1354. You still need the OR-method if you want to set more than one bit fast :
  1355.      x|=x| OR &X1010          ! set bit 1 and 3
  1356. The mask &X1010 is used to set bits 1 and 3. Compare this with the AND-
  1357. method, where 0 is used to clear a bit, while here 1 is used to set a bit. 
  1358. You can use OR not only as an operator, but also as a function :
  1359.      y|=OR(x|,&X1010)
  1360.  
  1361.  
  1362. BCHG
  1363.  
  1364. Instead of BCHG you should use the XOR-method if you want to change more 
  1365. than one bit (with a mask) :
  1366.      x|=x| XOR &X1110         ! change bit 1-3
  1367. XOR can be used as a function as well.
  1368.  
  1369.  
  1370. LOG
  1371.  
  1372. Logarithms with a base other than 10 or e are computed as follows :
  1373.      LOG(x)/LOG(base)
  1374.  
  1375.  
  1376. SINQ and COSQ
  1377.  
  1378. If you are going to convert SIN (or COS) into SINQ (COSQ), you'll have to 
  1379. change from radials to degrees. For example, you would convert SIN(x) to 
  1380. SINQ(DEG(x)). Although SINQ is about five times faster than SIN, this 
  1381. extra computation makes the difference a little less spectacular. If you 
  1382. are lucky, the variable already is in degrees, so you can use SINQ 
  1383. immediately. SINQ and COSQ should not be used if you need very accurate 
  1384. results, only if you plot the result and are not going to use it for 
  1385. further computations. Examine the difference between the use of SIN/COS 
  1386. and SINQ/COSQ to see if the less accurate result is acceptable. In High 
  1387. resolution try something like this :
  1388.      fac#2*PI/639
  1389.      DRAW 0,200
  1390.      FOR x=0 TO 639
  1391.        y#=SIN(x*fac#)
  1392.        DRAW TO x,200+y#*200
  1393.      NEXT x
  1394.      ~INP(2)
  1395.      CLS
  1396.      '
  1397.      DRAW 0,200
  1398.      FOR x=0 TO 639
  1399.        y#=SINQ(DEG(x*fac#))
  1400.        DRAW TO x,200+y#*200
  1401.      NEXT x
  1402.      ~INP(2)
  1403.      CLS
  1404.      '
  1405.      fac#=360/639
  1406.      DRAW 0,200
  1407.      FOR x=0 TO 639
  1408.        y#=SINQ(x*fac#)
  1409.        DRAW TO x,200+y#*200
  1410.      NEXT x
  1411.      ~INP(2)
  1412.  
  1413.  
  1414. EQV
  1415.  
  1416. EQV doesn't work properly. EQV(0,-1) should be 0, but equals -65536. The 
  1417. bits 16-31 are always set: EQV seems to look at the bits 0-15 only. 
  1418.  
  1419.  
  1420. CARD and SWAP
  1421.  
  1422. If a 4-byte integer (postfix %) consists of two words, you can extract 
  1423. these with :
  1424.      low.word=CARD(x%)
  1425.      high.word=CARD(SWAP(x%))
  1426. Both words are interpreted as positive numbers.
  1427.  
  1428. Unfortunately, there is no analogue function to swap the low and high 
  1429. byte of a word. That would be useful if you want to convert a word 
  1430. into/from Intel-format (MS-DOS). Rotating 8 bits should do the trick :
  1431.      FUNCTION intel.word(x%)
  1432.        RETURN CARD(ROR&(x%,8))     ! swap low/high byte
  1433.      ENDFUNC
  1434. Now you should be able to extract the low and high byte of a word :
  1435.      low.byte|=BYTE(x)
  1436.      high.byte|=BYTE(@intel.word(x))
  1437.  
  1438.  
  1439. MAX
  1440.  
  1441. This is how you could find the highest value in a word-array :
  1442.      PROCEDURE max.array(VAR proc(),high)
  1443.        ' *** return highest value of array proc()
  1444.        LOCAL last,n
  1445.        last=DIM?(proc())-1
  1446.        high=proc(1)                ! proc(0) ignored
  1447.        FOR n=2 TO last
  1448.          high=MAX(high,proc(n))
  1449.        NEXT n
  1450.      RETURN
  1451. I often store special information in the element with index 0.
  1452.  
  1453.  
  1454. Correlation
  1455.  
  1456. Use the Procedure Correlate to determine the correlation between two 
  1457. arrays.
  1458.                                7.  STRINGS
  1459.  
  1460.  
  1461. INSTR
  1462.  
  1463. The command INSTR(a$,b$,i) always returns '1' if a$=b$. For i=1 that's 
  1464. fine, but not for i>1. Don't blame me, I'm just the messenger.
  1465.  
  1466.  
  1467. LSET and RSET
  1468.  
  1469. If you use LSET or RSET, the string is padded with spaces :
  1470.      a$="  345"
  1471.      LSET a$="12"
  1472.      PRINT a$       ! the interpreter prints "12   ", not "12345"
  1473.  
  1474. You can use RSET for right justification of columns :
  1475.      f$=SPACE$(10)
  1476.      FOR i=1 TO 10
  1477.        RSET f$=text$(i)
  1478.        PRINT f$
  1479.      NEXT i
  1480.  
  1481.  
  1482. Parser
  1483.  
  1484. Parsing a string, you will frequently have to split the string into the 
  1485. target$, the string before and the string after that target$. The 
  1486. following functions could be helpful :
  1487.      FUNCTION before$(source$,target$)
  1488.        ' *** returns part of source$ before target$
  1489.        ' *** returns complete source$ if no target$ found
  1490.        LOCAL p
  1491.        p=INSTR(source$,target$)
  1492.        IF p=0
  1493.          RETURN source$
  1494.        ELSE
  1495.          RETURN LEFT$(source$,p-1)
  1496.        ENDIF
  1497.      ENDFUNC
  1498.      '
  1499.      FUNCTION after$(source$,target$)
  1500.        ' *** returns part of source$ after target$
  1501.        ' *** returns nullstring if no target$ found
  1502.        LOCAL p
  1503.        p=INSTR(source$,target$)
  1504.        IF p=0
  1505.          RETURN ""
  1506.        ELSE
  1507.          RETURN MID$(source$,p+LEN(target$))
  1508.        ENDIF
  1509.      ENDFUNC
  1510.  
  1511.  
  1512.                             8.  KEYBOARD INPUT
  1513.  
  1514.  
  1515. INKEY$
  1516.  
  1517. All keypresses are saved in the keyboard-buffer. If you don't want INKEY$ 
  1518. to read an "old" key, you should first clear the buffer :
  1519.      REPEAT
  1520.      UNTIL INKEY$=""     ! clear keyboard-buffer
  1521.      key$=""
  1522.      REPEAT
  1523.        key$=INKEY$       ! wait for new key
  1524.      UNTIL key$<>""
  1525.  
  1526. In the following table you'll find a few useful decimal ASCII-codes you 
  1527. can use after 'key$=INKEY$'. In the third column the hexadecimal scan-code 
  1528. of the key is also mentioned (see paragraph 'KEYGET'). 
  1529.  
  1530.      key                   ASC(key$)       scancode
  1531.      <Backspace>               8             &H0E
  1532.      <Tab>                     9             &H0F
  1533.      <Return> and <Enter>     13             &H1C and &H72
  1534.      <Esc>                    27             &H01
  1535.      <Delete>                127             &H53
  1536.  
  1537.      key               ASC(RIGHT$(key$))
  1538.      <F1>                     59             &H3B
  1539.      <F10>                    68             &H44
  1540.      <Shift> <F1>             84             &H54
  1541.      <Shift> <F10>            93             &H5D
  1542.      <Help>                   98             &H62
  1543.      <Undo>                   97             &H61
  1544.      <Insert>                 82             &H52
  1545.      <ClrHome>                71             &H47
  1546.      <Left arrow>             75             &H4B
  1547.      <Right arrow>            77             &H4D
  1548.      <Up arrow>               72             &H48
  1549.      <Down arrow>             80             &H50
  1550.  
  1551. Keys in the second part of this table return a 2-byte value after INKEY$. 
  1552. You only need the low byte, the high byte is &H00. That's why a Standard 
  1553. Global like help$ is defined as 'CHR$(0)+CHR$(98)'. Then it's easy to 
  1554. check if <Help> was pressed :
  1555.      IF key$=help$
  1556.        (...)                  ! <Help>
  1557.      ENDIF
  1558. Otherwise, you have to test as follows :
  1559.      IF ASC(RIGHT$(key$))=98
  1560.        (...)                  ! <Help>
  1561.      ENDIF
  1562. However, read the paragraph 'KEYGET' for the ultimate keypress-processor.
  1563.  
  1564. If you are just waiting for any keypress, you could use either of the 
  1565. following methods (clear the keyboard-buffer first) :
  1566.      ~INP(2)             ! my favourite
  1567.      '
  1568.      KEYGET code%        ! perhaps this is clearer in a listing
  1569.      '
  1570.      REPEAT              ! a loop is also possible
  1571.      UNTIL LEN(INKEY$)
  1572. The latter method is needed if you are waiting for any keypress or any 
  1573. mouse-click :
  1574.      REPEAT
  1575.      UNTIL LEN(INKEY$) OR MOUSEK
  1576.  
  1577.  
  1578. INPUT
  1579.  
  1580. If you don't want the question mark to appear after INPUT, use :
  1581.      LOCATE col,lin
  1582.      INPUT "",txt$
  1583. The nullstring and the comma are essential. Most of the time you'll need 
  1584. something like :
  1585.      LOCATE col,lin
  1586.      INPUT "Enter your name : ",name$
  1587. But if the instruction-line is not the same as the INPUT-line, use :
  1588.      PRINT AT(col1,lin1);"Enter your name :"
  1589.      LOCATE col2,lin2
  1590.      INPUT "",name$
  1591.  
  1592. After INPUT, the user can press <Insert> to switch between Insert-mode and 
  1593. Overwrite-mode. I have not been able to discover how to input character-
  1594. codes 0-31 after INPUT. It's not important anyway, but I read somewhere 
  1595. you could use <Alternate> for this purpose. The Alternate-method can be 
  1596. used for character-codes 128-255 (not 127). In the following table you'll 
  1597. find some important characters with the decimal ASCII-code :
  1598.  
  1599.   character ASCII-code   character ASCII-code   character ASCII-code
  1600.  
  1601.      á    -    160          é    -    130          í    -    161
  1602.      à    -    133          è    -    138          ì    -    141
  1603.      ä    -    132          ë    -    137          ï    -    139
  1604.      â    -    131          ê    -    136          î    -    140
  1605.  
  1606.      ó    -    162          ú    -    163          ÿ    -    152
  1607.      ò    -    149          ù    -    151          ß    -    158
  1608.      Ö    -    148          ü    -    129
  1609.      ô    -    147          û    -    150
  1610.  
  1611.      α    -    224          ≡    -    240          ½    -    171
  1612.      β    -    225          ±    -    241          ¼    -    172
  1613.      δ    -    235          ≥    -    242          ²    -    253
  1614.      µ    -    230          ≤    -    243
  1615.      π    -    227          ÷    -    246
  1616.      τ    -    231          ≈    -    247
  1617.  
  1618.      ¢    -    155          ©    -    189
  1619.      £    -    156          §    -    221
  1620.      ƒ    -    159
  1621. If you want to use one of these characters after INPUT, you should hold 
  1622. <Alternate> down, enter the code, and release <Alternate>. I hope your 
  1623. printer-driver could digest this table...
  1624.  
  1625. You can use <Backspace>, <Delete>, <Left arrow> and <Right arrow> on an 
  1626. INPUT-line, but also :
  1627.      <Up arrow>     - cursor to start of input-line
  1628.      <Down arrow>   - cursor to end of line
  1629.      <Esc>          - erase line
  1630. The first two feel slightly unnatural, I would prefer it the other way: up 
  1631. to end, down to start.
  1632.  
  1633. Both INPUT and LINE INPUT use a special cursor, so it doesn't make much 
  1634. sense to use XBIOS 21 (Curscon) to do something interesting with the TOS-
  1635. cursor.
  1636.  
  1637.  
  1638. INPUT$
  1639.  
  1640. For the input of a secret password, you could use something like :
  1641.      PRINT "type password (5 characters) : ";
  1642.      code$=INPUT$(5)
  1643. The password does not appear on the screen. 
  1644.  
  1645.  
  1646. LINE INPUT
  1647.  
  1648. LINE INPUT uses the underscore (_) as the cursor in a window. After you 
  1649. press <Return>, the underscore is not completely erased. The rightmost 
  1650. pixel remains visible. I think this is a GEM-bug.
  1651.  
  1652.  
  1653. KEYTEST
  1654.  
  1655. The KEYTEST-function does not respond to keys such as <Help>, <Undo>, etc.
  1656.  
  1657.  
  1658. KEYGET
  1659.  
  1660. KEYGET waits for a keypress, just like INP(2). But KEYGET is far more 
  1661. flexible, because it returns the ASCII-code and the scan-code of any key 
  1662. and also the state of the special keys <Shift>, <Control>, <Alternate> and 
  1663. <CapsLock>. Consult your manual for tables of ASCII-codes and scan-codes 
  1664. (in the paragraph 'INKEY$' you already encountered some important codes). 
  1665. Study the following example to get an impression of the easy way you can 
  1666. examine all keypresses with KEYGET :
  1667.  
  1668.      @initio_keyget        ! assign variables to the three codes
  1669.      '
  1670.      DO
  1671.        KEYGET get_code%
  1672.        @keyget             ! process keypress there (not included)
  1673.      LOOP
  1674.      '
  1675.      PROCEDURE initio_keyget
  1676.        ABSOLUTE ascii|,V:get_code%+3
  1677.        ABSOLUTE scan|,V:get_code%+1
  1678.        ABSOLUTE status|,V:get_code%
  1679.      RETURN
  1680.  
  1681. You will have to write your own Keyget-Procedure. You can check if any of 
  1682. the special keys has been pressed, by using BTST(status|,bit) :
  1683.      bit 0 = Right <Shift>
  1684.      bit 1 = Left <Shift>
  1685.      bit 2 = <Control>
  1686.      bit 3 = <Alternate>
  1687.      bit 4 = <CapsLock>
  1688. You could discover if the user had pressed <Control> <Down arrow> with :
  1689.      IF scan|=&H50 AND BTST(status|,2)
  1690.        (...)
  1691.      ENDIF
  1692.  
  1693. If you are only interested in monitoring the five special keys, you could 
  1694. use BIOS 11 (Kbshift) as well :
  1695.      status|=BIOS(11,-1)
  1696. Use the same table as above to test if bit 0-4 is set.
  1697.  
  1698. You are advised to clear the keyboard-buffer before leaving the Procedure 
  1699. Keyget.
  1700.  
  1701. In most cases the scan-code of a key is the same, whether you pressed a 
  1702. special key simultaneously or not. But watch out for the following 
  1703. exceptions! For <Shift> <F1> to <Shift> <F10> the scan-codes &H54 to &H5D 
  1704. are returned (not &H3B to &H44). On an MS-DOS computer these codes are 
  1705. used for the keys F11 to F20. The combinations <Control> <Left Arrow> 
  1706. (&H73) and <Control> <Right Arrow> (&H74) also have special codes. Blame 
  1707. MS-DOS. The combinations <Alternate> <1> to <Alternate> <=> have the 
  1708. special codes &H78 to &H83. That's ALT1 to ALT= for MS-DOS.
  1709.  
  1710.  
  1711. KEYLOOK
  1712.  
  1713. According to an unconfirmed report, KEYLOOK does not function properly 
  1714. with the pre-Blitter TOS.
  1715.  
  1716.  
  1717. KEYPRESS
  1718.  
  1719. KEYPRESS uses the same 4-byte format as KEYGET: &Hccss00aa. In it you 
  1720. will recognize the ASCII-code (&Haa), the scan-code (&Hss) and the code 
  1721. for the special keys (&Hcc). If you want to simulate the pressing of a key 
  1722. in an Alert box, you will have to send both the ASCII-code and the scan-
  1723. code. Use &H1C000D to simulate the pressing of <Return>. Or &H04620062 for 
  1724. <Control> <Help>, although that certainly won't help in an Alert box. If 
  1725. you don't need the scan-code (e.g. with INPUT), you can use just KEYPRESS 
  1726. &Haa.
  1727.  
  1728.  
  1729. KEYDEF
  1730.  
  1731. The editor always uses KEYPAD &X101110, so you will have to set bit 4 
  1732. yourself (e.g. KEYPAD &X10000) before you will be able to use KEYDEF in 
  1733. your program.
  1734.  
  1735.  
  1736. Keyboard
  1737.  
  1738. As far as I know, there are four different keyboards available : USA 
  1739. (QWERTY), English (QWERTY), German (QWERTZ) and French (AZERTY). The key 
  1740. with scan-code &H2B (to the right of <Return>) has a different ASCII-code 
  1741. in each version :
  1742.      version   ASCII-code     character
  1743.      USA        &H5C (92)         \
  1744.      English    &H23 (35)         #
  1745.      German     &H7E (126)        ~
  1746.      French     &H40 (64)         @
  1747. You could use XBIOS 16 (Keytbl) to determine the keyboard-version :
  1748.      PROCEDURE keyboard.version
  1749.        SELECT PEEK(LPEEK(XBIOS(16,L:-1,L:-1,L:-1))+&H2B)
  1750.        CASE &H5C
  1751.          usa.keybrd!=TRUE
  1752.        CASE &H23
  1753.          english.keybrd!=TRUE
  1754.        CASE &H7E
  1755.          german.keybrd!=TRUE
  1756.        CASE &H40
  1757.          french.keybrd!=TRUE
  1758.        ENDSELECT
  1759.      RETURN
  1760.  
  1761. You should take into account the differences between the keyboard-versions 
  1762. if you are writing a program that should run smoothly in any country.
  1763.  
  1764. In the following table I have gathered all keys that have not the same 
  1765. meaning on the four keyboard-versions :
  1766.  
  1767.      scancode      USA     English    German    French
  1768.        &H0C         -         -         ß         )      
  1769.        &H0D         =         =         -         '
  1770.        &H10         Q         Q         Q         A
  1771.        &H11         W         W         W         Z
  1772.        &H15         Y         Y         Z         Y
  1773.        &H1A         [         [         Ü         [
  1774.        &H1B         ]         ]         +         ]
  1775.        &H1E         A         A         A         Q
  1776.        &H27         ;         ;         ö         M
  1777.        &H28         '         '         Ä         \
  1778.        &H29         `         `         #         `
  1779.        &H2B         \         #         ~         @
  1780.        &H2C         Z         Z         Y         W
  1781.        &H32         M         M         M         ,
  1782.        &H33         ,         ,         ,         ;
  1783.        &H34         .         .         .         :
  1784.        &H35         /         /         -         =
  1785.        &H60        none       \         <         <
  1786.  
  1787. If you are going to use any scan-code from this table, you should be very 
  1788. careful. It's not nice to ask a German user to press <Y>, but test for 
  1789. scan-code &H15 in your program...
  1790.  
  1791. If you insist on doing things the hard way, you can find the ASCII-value 
  1792. that is assigned to a key with XBIOS 16. Actually there are three tables: 
  1793. one for a normal keypress, one for a shifted key and one for a keypress 
  1794. with CapsLock on :
  1795.      keytbl%=LPEEK(XBIOS(16,L:-1,L:-1,L:-1))
  1796.      shift%=keytbl%+&H80
  1797.      capslock%=shift%+&H80
  1798. Now you can find the ASCII-code for any scan-code (< &H80) :
  1799.      ascii=PEEK(keytbl%+scancode)       ! normal key
  1800.      ascii=PEEK(shift%+scancode)        ! shifted key
  1801.      ascii=PEEK(capslock%+scancode)     ! CapsLock on
  1802.  
  1803.  
  1804. Keyclick, Keyrepeat and CapsLock
  1805.  
  1806. Normally, you need the Keyclick as an audible feedback. Sometimes you have 
  1807. to switch the Keyclick off, e.g. while an XBIOS 32 song is playing :
  1808.      PROCEDURE key.click(switch!)
  1809.        IF switch!
  1810.          SPOKE &H484,BSET(PEEK(&H484),0)     ! keyclick on
  1811.        ELSE
  1812.          SPOKE &H484,BCLR(PEEK(&H484),0)     ! keyclick off
  1813.        ENDIF
  1814.      RETURN
  1815.  
  1816. If your program reacts slowly after a keypress, you probably have to 
  1817. switch the Keyrepeat temporarily off :
  1818.      PROCEDURE key.repeat(switch!)
  1819.        IF switch!
  1820.          SPOKE &H484,BSET(PEEK(&H484),1)     ! key-repeat on
  1821.        ELSE
  1822.          SPOKE &H484,BCLR(PEEK(&H484),1)     ! key-repeat off
  1823.        ENDIF
  1824.      RETURN
  1825.  
  1826. You can switch CapsLock on or off with :
  1827.      PROCEDURE caps(switch!)
  1828.        IF switch!
  1829.          ~BIOS(11,BSET(BIOS(11,-1),4))       ! CapsLock on
  1830.        ELSE
  1831.          ~BIOS(11,BCLR(BIOS(11,-1),4))       ! CapsLock off
  1832.        ENDIF
  1833.      RETURN
  1834.  
  1835.  
  1836.  
  1837.                             9.  SCREEN OUTPUT
  1838.  
  1839.  
  1840. PRINT
  1841.  
  1842. It is very important to know if PRINT will be used on the so-called TOS-
  1843. screen (no windows opened), or in a window. TOS emulates the VT52-terminal 
  1844. of Digital Equipment, so if you PRINT on the TOS-screen, the VT52-codes 
  1845. will be interpreted as commands. But in a window these codes are printed 
  1846. as characters!
  1847.  
  1848. In both High and Medium resolution you can PRINT 25 lines of 80 
  1849. characters, but in Low resolution it's 25 lines of 40 characters only.
  1850.  
  1851. Normally you can't PRINT a character at position (80,25) in High or Medium 
  1852. resolution, or at (40,25) in Low resolution. Try the following :
  1853.      PRINT AT(80,25);"X";
  1854. and you will see that a linefeed is executed automatically, in spite of 
  1855. the semicolon after "X". On the TOS-screen you can put a character at this 
  1856. position by using the VT52-command 'wrap off' :
  1857.      PRINT AT(80,25);"*wX";        ! use the Escape-character instead of *
  1858. After 'Esc w' the linefeed is suppressed. The easiest way to enter the 
  1859. Escape-character in the GFA-editor is to hold <Alternate> down and then to
  1860. enter <2> <7>. If you PRINT a string that doesn't fit on the current line, 
  1861. the remaining characters are either printed on the next line ('Esc v', the 
  1862. default in the interpreter, not in a compiled program), or discarded
  1863. ('Esc w'). Actually, after 'Esc w' all characters up to the first CHR$(10) 
  1864. or CHR$(13) are discarded.
  1865.  
  1866. It's impossible to PRINT characters with ASCII-code 0-31 on the TOS-
  1867. screen. However, you can print any character with :
  1868.      OUT 5,code
  1869. If necessary, use LOCATE first.
  1870.  
  1871. After opening a window (OPENW x) the command DEFTEXT will change size and 
  1872. colour of PRINTed text as well! One advantage is that you can now PRINT in 
  1873. different colours on the screen.
  1874.  
  1875. On the TOS-screen, all PRINTed text has the same colour. This colour is 
  1876. determined by colour-index 1 and is also used for the Alert-box and the 
  1877. Fileselector. The background on the screen is determined by colour-index 
  1878. 0. This colour is used after CLS.
  1879.  
  1880. It is possible to PRINT in different colours on the TOS-screen, by using 
  1881. the VT52-code 'Esc b'. The background of PRINTed text can be changed with 
  1882. VT52-code 'Esc c'. Use the following functions to experiment :
  1883.      DEFFN ink$(color)=CHR$(27)+"b"+CHR$(color)
  1884.      DEFFN paper$(color)=CHR$(27)+"c"+CHR$(color)
  1885. Use the colour-table from the paragraph 'SETCOLOR' or be prepared to 
  1886. become very frustrated. I use the Standard Array color.index() as the 
  1887. colour-table in my programs, so I change the colour of the PRINTed text or 
  1888. the back-ground with the Standard Functions :
  1889.      DEFFN ink$(color)=CHR$(27)+"b"+CHR$(color.index(color))
  1890.      DEFFN paper$(color)=CHR$(27)+"c"+CHR$(color.index(color))
  1891. Remember, the VT52-codes have to be PRINTed to become effective, like 
  1892. this :
  1893.      PRINT @ink$(red);@paper$(green);" this text is eye-catching "
  1894. Note the spaces at beginning and end of the string to emphasize the text-
  1895. colour against the background-colour. Of course you have to declare the 
  1896. variables red and green first (usually colour-index 2 and 3; or if you 
  1897. don't use the VDI colour-index, try the numbers 1 and 2). I define the 
  1898. default colours as Standard Globals in my programs. Before I forget, it 
  1899. won't work in High resolution. Sorry, couldn't resist that one.
  1900.  
  1901. In order to catch the eye of the user in High resolution you can PRINT 
  1902. reverse on the TOS-screen :
  1903.      PRINT "this is *p IMPORTANT *q"    ! enter Esc instead of *
  1904. Enter the Escape-character in the usual way. Note again the extra space 
  1905. both before and after the word that should stand out. Of course you could 
  1906. also use CHR$(27) :
  1907.      PRINT "this is ";CHR$(27);"p IMPORTANT ";CHR$(27);"q"
  1908. More difficult to read on the screen, but easier to Llist. I use the 
  1909. Standard Function Rev$ in all programs :
  1910.      DEFFN rev$(txt$)=CHR$(27)+"p"+txt$+CHR$(27)+"q"
  1911.  
  1912. If you use a comma with PRINT, the cursor will jump to the next tabulator-
  1913. stop. Tab-stops are at position 1, 17, 33, 49 and 65. Try the following to 
  1914. see what I mean (in High or Medium resolution) :
  1915.      PRINT "1","17","33","49","65","1","17"
  1916. If you use the comma after the last tab-stop, a linefeed is executed and 
  1917. the cursor jumps to the first tab-stop on the next line.
  1918.  
  1919. The easiest way to use double quotes is by using double double quotes 
  1920. (read this twice to make sure you understand it) :
  1921.      PRINT "double quotes printed the ""easy"" way"
  1922. In a DATA-line a single double quote suffices :
  1923.      DATA "look Ma, "double quotes" again"
  1924. Or, simply :
  1925.      DATA look Ma, "double quotes" again
  1926.  
  1927. Try the Procedure Fastprint in High resolution if you find PRINT too slow. 
  1928. This Procedure prints about four times faster! VT52-commands are ignored, 
  1929. because characters are copied straight from the font-table to the screen.
  1930.  
  1931.  
  1932. LOCATE
  1933.  
  1934. The syntax of PRINT AT and LOCATE is now less confusing :
  1935.      PRINT AT(column,line)
  1936.      LOCATE column,line
  1937. In older versions of GFA-Basic it was LOCATE line,column. Check this if 
  1938. you run an old program and text is PRINTed on the wrong place.
  1939.  
  1940.  
  1941. PRINT TAB
  1942.  
  1943. PRINT TAB behaves strangely if the position is greater than 80. Try the 
  1944. following in High or Medium resolution :
  1945.      FOR i=0 TO 30
  1946.        PRINT TAB(i*20);i;
  1947.      NEXT i
  1948. One way to solve this problem is :
  1949.      PRINT TAB(MOD(i*20,80));i;         ! do use semicolons
  1950. But I think this is a GFA-bug that probably will be corrected in future 
  1951. versions.
  1952.  
  1953. You can combine TAB with PRINT AT and with PRINT USING :
  1954.      PRINT AT(1,1);"1";TAB(40);"40"
  1955.      PRINT TAB(40);USING "##",40
  1956.  
  1957.  
  1958. Setscreen (XBIOS 5)
  1959.  
  1960. With XBIOS 5 (Setscreen) it is possible to change the resolution from Low 
  1961. to Medium and from Medium to Low. Unfortunately, GEM ignores the switch, 
  1962. so GEM-commands (e.g. ALERT, TEXT, MOUSE) do not work properly! But you 
  1963. could change from Low to Medium resolution to show text on the TOS-screen 
  1964. with PRINT (and VT52-commands). Most users will be grateful for the 
  1965. improved readability of the text :
  1966.      ~XBIOS(5,L:-1,L:-1,1)    ! switch from Low to Medium
  1967.      (...)                    ! print text in Medium resolution
  1968.      ~XBIOS(5,L:-1,L:-1,0)    ! and go back to Low 
  1969. If you change the resolution, the VT52-emulator is automatically 
  1970. initialised. You'll probably have to adjust the palette before you can 
  1971. read the text without sun-glasses. Don't forget to save and restore the 
  1972. old palette.
  1973.  
  1974. XBIOS 5 is very useful if you would like to draw on a screen before 
  1975. showing it to the user. Drawing on an "invisible" screen is indeed 
  1976. possible, because the operating system uses two screens: the physical 
  1977. screen (visible on your monitor) and the logical screen (usually, but not 
  1978. necessarily, the same as the physical screen). All graphical (GEM-)com-
  1979. mands, including the TEXT-command, are always sent to the logical screen. 
  1980. But TOS will send PRINT-commands to the physical screen, unless you've 
  1981. opened a window! If the address of logical and physical screen is not the 
  1982. same, you have your invisible screen (except for PRINTing on the TOS-
  1983. screen). The address of the logical screen must be a multiple of 256. 
  1984. Study the Procedures Initio.logical.screen, Swap.screen and 
  1985. Restore.physical.screen to see how you could use the described method for 
  1986. animation :
  1987.      PROCEDURE initio.logical.screen
  1988.        ' *** global :   SCREEN.1%   SCREEN.2%
  1989.        DIM screen.2|(32256)               
  1990.        screen.2%=VARPTR(screen.2|(0))
  1991.        screen.2%=screen.2%+256-(screen.2% MOD 256)
  1992.        screen.1%=physbase%
  1993.        ~XBIOS(5,L:screen.2%,L:-1,-1)  ! invisible screen.2 is now active
  1994.      RETURN
  1995.      ' 
  1996.      PROCEDURE swap.screen
  1997.        ' *** physical and logical screen are swapped
  1998.        SWAP screen.1%,screen.2%
  1999.        VSYNC                                   ! avoid flash
  2000.        ~XBIOS(5,L:screen.2%,L:screen.1%,-1)    ! swap the screens
  2001.      RETURN
  2002.      ' 
  2003.      PROCEDURE restore.physical.screen
  2004.        ~XBIOS(5,L:physbase%,L:physbase%,-1)
  2005.      RETURN
  2006.  
  2007. On some ST-computers XBIOS 5 does not function properly after installation 
  2008. of a RAM-disk. In that case you could change the address of the logical 
  2009. screen with :
  2010.      VSYNC
  2011.      SLPOKE &H45E,adr%
  2012.  
  2013.  
  2014. Font
  2015.  
  2016. TOS has three built-in system-fonts. The default PRINT-font for High 
  2017. resolution is the 8x16 font (equals DEFTEXT ,,,13 for TEXT), while the 8x8 
  2018. font (equals DEFTEXT ,,,6) is used in Medium and Low resolution. You can 
  2019. switch between these two fonts with the following Procedures :
  2020.      PROCEDURE font.8x16
  2021.        LOCAL a$,adr%
  2022.        a$=MKI$(&HA000)+MKI$(&H2009)+MKI$(&H4E75)   
  2023.        adr%=VARPTR(a$)
  2024.        adr%=C:adr%()         ! address of font-table
  2025.        {INTIN}={adr%+8}      ! pointer to 8x16 system-font 
  2026.        VDISYS 5,2,0,102      
  2027.      RETURN
  2028.      ' 
  2029.      PROCEDURE font.8x8
  2030.        LOCAL a$,adr%
  2031.        a$=MKI$(&HA000)+MKI$(&H2009)+MKI$(&H4E75)   
  2032.        adr%=VARPTR(a$)
  2033.        adr%=C:adr%()         ! address of font-table
  2034.        {INTIN}={adr%+4}      ! pointer to 8x8 system-font
  2035.        VDISYS 5,2,0,102      
  2036.      RETURN     
  2037. Both Procedures seem to have problems with the accessory QUICKST, but I 
  2038. never use it with GFA-Basic because there are other problems (INPUT) as 
  2039. well. If I don't use it, how did I discover this? Good question. The third 
  2040. font is used for icons, but for some reason can not become the current 
  2041. system-font. The VDI-function seems to work only with fonts containing 
  2042. characters of width 8 pixels. The function is not officially documented 
  2043. by Atari (?).
  2044.  
  2045. You can replace the system-font by a font that has been created with 
  2046. FONTKIT by Jeremy Hughes (4114 byte A1_xxxxx.FON file for High 
  2047. resolution). Use the Procedure Change.font for this purpose and call the 
  2048. Procedure Normal.font to restore the original system-font :
  2049.      PROCEDURE change.font
  2050.        ' *** global :   NEW.FONT!   NORMAL.FONT%
  2051.        LOCAL adr%,new.font%
  2052.        '
  2053.        ' *** load A1_xxxxx.FON file (4114 bytes) here
  2054.        INLINE new.font%,4114
  2055.        '
  2056.        adr%=L~A-22
  2057.        normal.font%={adr%}
  2058.        SLPOKE adr%,new.font%
  2059.        new.font!=TRUE
  2060.      RETURN
  2061.      '
  2062.      PROCEDURE normal.font
  2063.        IF new.font!
  2064.          SLPOKE L~A-22,normal.font%
  2065.          new.font!=FALSE
  2066.        ENDIF
  2067.      RETURN
  2068. I have not yet discovered how to use a FONTKIT-font with TEXT. Yes, I 
  2069. could load a new font after installing GDOS, but that's not what I'm 
  2070. looking for. Is there a quick and not-dirty way to convince GEM that a new 
  2071. font has been installed?
  2072.  
  2073. A font-table for the 8x16 font occupies 4096 bytes (16 bytes/character, 
  2074. 256 characters). A FONTKIT-font usually has a name attached at the end, 
  2075. that's why I reserve 4114 bytes. TOS ignores the name completely, it's 
  2076. only used by the accessory FONSEL.ACC. You can load any 4096-byte font in 
  2077. the Procedure Change.font, you don't even have to change 4114 into 4096. 
  2078. Although you lose 18 bytes if you don't.
  2079.  
  2080.  
  2081.                                10.  PRINTER
  2082.  
  2083.  
  2084. Printer ready
  2085.  
  2086. If you send data to your printer (HARDCOPY, LPRINT, etc.), your ST will 
  2087. wait 30 looooooong seconds if the printer happens to be not ready. Always 
  2088. check if the printer is ready before sending data to the printer, e.g. by 
  2089. calling the following Procedure :
  2090.      PROCEDURE printer.ready
  2091.        LOCAL k
  2092.        DO
  2093.          EXIT IF GEMDOS(17)
  2094.          ALERT 3," printer| | not ready !!",1," OK ",k
  2095.        LOOP
  2096.      RETURN
  2097.  
  2098.  
  2099. HARDCOPY
  2100.  
  2101. You can send a screendump to the printer by using the command HARDCOPY or 
  2102. by pressing <Alternate> <Help>. In both cases you can abort the screendump 
  2103. by pressing <Alternate> <Help>.
  2104.  
  2105. You can use CONTROL.ACC to change the printer-parameters. Don't forget to 
  2106. save the desktop, in order to store these parameters in the file 
  2107. DESKTOP.INF. Look for '#b' with your disk-editor if you're curious. The 
  2108. parameters will only be read from DESKTOP.INF if CONTROL.ACC is installed 
  2109. after a reset! I suggest the use of XBIOS 33 (Setprt) in a program instead 
  2110. of using CONTROL.ACC. For a screendump from the High resolution screen to 
  2111. an Epson-compatible printer, clear bit 1 and set bit 2 :
  2112.      PROCEDURE screendump
  2113.        ~XBIOS(33,&X100)    ! screendump to Epson(-compatible) printer
  2114.        HARDCOPY
  2115.      RETURN
  2116. If you set bit 2, TOS assumes you connected an Epson-printer (960 
  2117. pixels/line). Clear bit 2 and TOS assumes you have an Atari-printer (1280 
  2118. pixels/line). 
  2119.  
  2120. If you use HARDCOPY, the width/height ratio of the printout does not 
  2121. correspond with that of the screen. For a reasonably fast 1:1 screendump, 
  2122. study the Procedure High.screendump.epson (Epson FX-80, or other 9-pin 
  2123. Epson-compatible printer) or the Procedure High.screendump.star24 (24-pin 
  2124. Star LC24-10) :
  2125.      PROCEDURE high.screendump.star24
  2126.        LOCAL m$,b$,k,scrn.start%,col,b%,x,d%,p|,b1|,b2|,b3|,n
  2127.        lf$=CHR$(10)
  2128.        ff$=CHR$(12)
  2129.        DEFFN bit.image$(m,d)=CHR$(27)+"*"+CHR$(m)+CHR$(MOD(d,256))+
  2130.                                                                CHR$(d/256)
  2131.        DEFFN line.space$(n)=CHR$(27)+"3"+CHR$(n)   
  2132.        initialize$=CHR$(27)+"@"
  2133.        scrn.start%=XBIOS(2)
  2134.        '
  2135.        LPRINT initialize$;
  2136.        FOR col=0 TO 79
  2137.          b%=scrn.start%+col
  2138.          LPRINT SPC(8);              
  2139.          LPRINT @line.space$(24);   
  2140.          LPRINT @bit.image$(33,800);
  2141.          FOR x=399 TO 0 STEP -1
  2142.            d%=ADD(b%,MUL(x,80))
  2143.            p|=BYTE{d%}
  2144.            IF p|=0
  2145.              OUT 0,0,0,0,0,0,0
  2146.            ELSE
  2147.              CLR b1|,b2|,b3|
  2148.              IF BTST(p|,0)
  2149.                b1|=7
  2150.              ENDIF
  2151.              IF BTST(p|,1)
  2152.                ADD b1|,56
  2153.              ENDIF
  2154.              IF BTST(p|,2)
  2155.                ADD b1|,192
  2156.                b2|=1
  2157.              ENDIF
  2158.              IF BTST(p|,3)
  2159.                ADD b2|,14
  2160.              ENDIF
  2161.              IF BTST(p|,4)
  2162.                ADD b2|,112
  2163.              ENDIF
  2164.              IF BTST(p|,5)
  2165.                ADD b2|,128
  2166.                b3|=3
  2167.              ENDIF
  2168.              IF BTST(p|,6)
  2169.                ADD b3|,28
  2170.              ENDIF
  2171.              IF BTST(p|,7)
  2172.                ADD b3|,224
  2173.              ENDIF
  2174.              OUT 0,b3|,b2|,b1|,b3|,b2|,b1|
  2175.            ENDIF
  2176.          NEXT x
  2177.          LPRINT
  2178.          EXIT IF INKEY$=esc$
  2179.        NEXT col
  2180.        LPRINT ff$;
  2181.        LPRINT initialize$;
  2182.      RETURN
  2183.  
  2184. For a more flexible approach, study the Procedure Degas.screendump (Star 
  2185. LC24-10, possible formats : 27x17, 18x11, 13.5x8.5 or 9x5.5 cm).
  2186.  
  2187. It should be possible to send only a (GET-)rectangle to your printer with 
  2188. XBIOS 36 (Prtblk) or V_OUTPUT_WINDOW (VDI 5,Escape 21). Anybody out there 
  2189. who knows how?
  2190.  
  2191. Never, I repeat, never swap disks during a screendump, as this could be 
  2192. fatal for the new disk. TOS ignores the write-protect state during a 
  2193. screendump, so it will miss the disk-swap completely. TOS will use the old 
  2194. FAT for the new disk, and that usually is fatal (no pun intended).
  2195.  
  2196. If you have installed a GFA-Basic printer-driver (e.g. PTEPSON.PRG), a 
  2197. screendump seems to be impossible. The bit-image mode of the printer can't 
  2198. be used after the driver has been installed.
  2199.  
  2200.  
  2201. Printer-commands
  2202.  
  2203. Most matrix-printers recognize either IBM- or Epson-commands (or both). I 
  2204. use the following Procedure to define the most important printer-commands 
  2205. for my Star LC24-10. Adapt the definitions to your own printer, but stick 
  2206. to the names for the global variables and functions. Other users could 
  2207. then use your programs easily after replacing the Procedure Initio.printer 
  2208. with their own :
  2209.      PROCEDURE initio.printer
  2210.        ' *** initializes global printer-variables for Star LC24-10
  2211.        ' *** DIP-switch settings :
  2212.        '     1-1 OFF         2-1 ON
  2213.        '     1-2 ON          2-2 ON
  2214.        '     1-3 OFF         2-3 ON
  2215.        '     1-4 ON          2-4 ON
  2216.        '     1-5 ON          2-5 OFF
  2217.        '     1-6 ON          2-6 OFF
  2218.        '     1-7 ON          2-7 ON
  2219.        '     1-8 ON          2-8 ON
  2220.        '
  2221.        LOCAL c$,f$
  2222.        c$=CHR$(27)
  2223.        f$=CHR$(28)
  2224.        '
  2225.        draft.char$=c$+"x0"
  2226.        lq.char$=c$+"x1"
  2227.        '
  2228.        courier.style$=c$+"k0"+lq.char$
  2229.        prestige.style$=c$+"k2"+lq.char$
  2230.        orator.style$=c$+"k3"+lq.char$
  2231.        script.style$=c$+"k4"+lq.char$
  2232.        '
  2233.        normal.char$=c$+"q0"
  2234.        outlined.char$=c$+"q1"
  2235.        shadow.char$=c$+"q2"
  2236.        outlined.shadow.char$=c$+"q3"
  2237.        '
  2238.        italic.on$=c$+"4"
  2239.        italic.off$=c$+"5"
  2240.        '
  2241.        emphasized.on$=c$+"E"
  2242.        emphasized.off$=c$+"F"
  2243.        '
  2244.        underline.on$=c$+"-1"
  2245.        underline.off$=c$+"-0"
  2246.        '
  2247.        bold.draft$=draft.char$+emphasized.on$+double.on$
  2248.        bold.lq$=lq$+double.on$
  2249.        bold.off$=emphasized.off$+double.off$
  2250.        '
  2251.        superscript.on$=c$+"S0"
  2252.        superscript.off$=c$+"T"
  2253.        subscript.on$=c$+"S1"
  2254.        subscript.off$=c$+"T"
  2255.        '
  2256.        epson.set$=c$+"t0"
  2257.        ibm.set$=c$+"t1"+c$+"6"
  2258.        DEFFN special.on$(n)=c$+"\"+CHR$(MOD(n,256))+CHR$(DIV(n,256))
  2259.        DEFFN ibm.special$(n)=c$+"^"+CHR$(n)
  2260.        DEFFN epson.special$(n)=ibm.set$+@ibm.special$(n)+epson.set$  
  2261.        '
  2262.        pica$=c$+"P"
  2263.        '
  2264.        elite$=c$+"M"
  2265.        '
  2266.        condensed.on$=CHR$(15)
  2267.        condensed.off$=CHR$(18)
  2268.        '
  2269.        large.on$=c$+"W1"
  2270.        large.off$=c$+"W0"
  2271.        large.line$=CHR$(14)
  2272.        '
  2273.        courier.proportional$=courier.style$+c$+"p1"
  2274.        prestige.proportional$=prestige.style$+c$+"p1"
  2275.        proportional.off$=c$+"p0"
  2276.        '
  2277.        DEFFN master.mode$(n)=c$+"!"+CHR$(n)
  2278.        underline=128
  2279.        italic=64
  2280.        expanded=32
  2281.        LET double.strike=16
  2282.        emphasized=8
  2283.        condensed=4
  2284.        proportional=2
  2285.        elite=1
  2286.        '
  2287.        normal.size$=c$+"h"+CHR$(0)
  2288.        LET double.size$=c$+"h"+CHR$(1)
  2289.        quad.size$=c$+"h"+CHR$(2)
  2290.        LET double.height$=c$+"w1"
  2291.        normal.height$=c$+"w0"
  2292.        normal.width$=f$+"E"+CHR$(0)
  2293.        LET double.width$=f$+"E"+CHR$(1)
  2294.        triple.width$=f$+"E"+CHR$(2)
  2295.        '
  2296.        lf$=CHR$(10)
  2297.        DEFFN lf$(n)=c$+"f1"+CHR$(n)
  2298.        rev.lf$=c$+CHR$(10)
  2299.        '
  2300.        ff$=CHR$(12)
  2301.        rev.ff$=c$+CHR$(12)
  2302.        '
  2303.        justify.left$=c$+"a0"
  2304.        justify.right$=c$+"a2"
  2305.        justify.full$=c$+"a3"
  2306.        center$=c$+"a1"
  2307.        '
  2308.        reset$=c$+"@"
  2309.        '
  2310.      RETURN
  2311. Of course you could delete all variables you don't need in your program. 
  2312. And it really would be nice if everyone uses the proposed names. One of 
  2313. the strong points of Public Domain GFA-programs is that it's easy to adapt 
  2314. a program. Or rather, it should be easy. Using the above Procedure is one 
  2315. step in the right direction.
  2316.      
  2317.  
  2318.                                 11.  FILES
  2319.  
  2320.  
  2321. Floppy Write Test
  2322.  
  2323. You are advised to switch the Write Verify test off :
  2324.      SPOKE &H444,0       ! test off
  2325.      SPOKE &H444,1       ! test on (default)
  2326. According to experts like Dave Small and Bill Wilkinson the Verify test is 
  2327. a complete waste of valuable time if you write to a disk. 
  2328.  
  2329.  
  2330. Step Rate
  2331.  
  2332. You will find the current step-rate of your drive with :
  2333.      PRINT DPEEK(&H440)
  2334. The following values are possible :
  2335.      0 -  6 ms
  2336.      1 - 12 ms
  2337.      2 -  2 ms
  2338.      3 -  3 ms (default)
  2339. The operating system only looks at this value after a reset (?). For an 
  2340. external 5.25"-drive you probably have to use 12 ms.
  2341.  
  2342.  
  2343. RAM-disk
  2344.  
  2345. Drive D is often reserved for a RAM-disk. GFA will recognize a RAM-disk 
  2346. with DFREE(4) only if it was already present at the time the interpreter 
  2347. was loaded. 
  2348.  
  2349. After switching off your 1040 ST you should wait at least 15 seconds 
  2350. before switching on again. Otherwise an old RAM-disk (or something else in 
  2351. RAM, e.g. a virus...) may still be present when you switch your computer 
  2352. on again.
  2353.  
  2354. If a RAM-disk is not installed properly after a reset, the reason could be 
  2355. hidden in the drive bit-table at &H4C2. The old TOS does not clear this 
  2356. table and a RAM-disk can only be installed as drive D if bit 3 is cleared. 
  2357. By the way, use drive C (bit 2) only for a harddisk.
  2358.  
  2359.  
  2360. DIR$()
  2361.  
  2362. Use GEMDOS 25 (Dgetdrv) to find the current drive and combine this with 
  2363. DIR$(drive) to find the current path :
  2364.      drive=GEMDOS(25)         ! drive 0 - 15
  2365.      drive$=CHR$(65+drive)    ! drive A - P
  2366.      p$=DIR$(drive+1)
  2367.      IF p$=""
  2368.        path$=drive$+":\"      ! main directory
  2369.      ELSE
  2370.        path$=drive$+":"+p$+"\"
  2371.      ENDIF
  2372. With DIR$(0) you'll find the path of the current drive, not necessarily 
  2373. drive A. DIR$(1) returns the path of drive A. GEMDOS remembers the last 
  2374. used path for all available drives. See also the Standard Procedure 
  2375. Get.path.
  2376.  
  2377. If you run GFA-Basic from the main directory and load a GFA-program from a 
  2378. folder, DIR$(0) will return the nullstring (""), not the folder. After 
  2379. using CHDIR with the folder-name, the correct path will be returned. I use 
  2380. CHDIR in the Shell-programs, so the Standard Global default.path$ will 
  2381. contain the path of the GFA-program. This makes life easier if you want to 
  2382. load data-files from the same folder, but don't know the precise path when 
  2383. you write the program. It would be nice if you could determine the path of 
  2384. the running GFA-program in the program itself.
  2385.  
  2386. You can make an array-table of available drives with the aid of BIOS 10 
  2387. (Drvmap) :
  2388.      DIM drive!(15)
  2389.      SELECT DPEEK(&H4A6)
  2390.      CASE 1
  2391.        drive!(0)=TRUE
  2392.      CASE 2
  2393.        drive!(0)=TRUE
  2394.        drive!(1)=TRUE
  2395.      ENDSELECT
  2396.      table%=BIOS(10)
  2397.      FOR n=2 TO 15
  2398.        IF BTST(table%,n)
  2399.          drive!(n)=TRUE
  2400.        ENDIF
  2401.      NEXT n
  2402.  
  2403. You can check if a harddisk is connected with :
  2404.      IF PEEK(&H472)<>0
  2405.        harddisk!=TRUE
  2406.      ENDIF
  2407.  
  2408.  
  2409. DIR and FILES
  2410.  
  2411. After DIR, FILES, TRON or DUMP you can slow down the scrolling with 
  2412. <CapsLock>. You can temporarily stop the scrolling by holding down the 
  2413. right <Shift>-key. The output after DIR fits on any screen, but the FILES-
  2414. output is too wide for Low resolution. DIR will show only files in the 
  2415. current directory. FILES will also show folders (marked with *). With DIR 
  2416. (and FILESELECT) you will not be able to see "hidden" files or "system" 
  2417. files, but FILES will show all files. You can also search for hidden 
  2418. and/or system files with FSFIRST and FSNEXT by setting bit 1 and/or bit 2 
  2419. of the attribute-byte.
  2420.  
  2421. Perhaps you have noticed that after the command FILES the first two lines 
  2422. are peculiar if you happen to be in a folder. The first "name" in a folder 
  2423. is always '.' (one dot) and the second always '..' (two dots). Time and 
  2424. date are incorrect, because the authors of (the old) TOS forgot to convert 
  2425. these to MS-DOS format. In case of nested folders, the operating system 
  2426. finds the preceding folder through a pointer of the '..'-file. That's why 
  2427. you can use 'CHDIR ..' to return to the preceding folder. Don't try this 
  2428. in the main directory, or you'll get an error.
  2429.  
  2430.  
  2431. FSFIRST and FSNEXT
  2432.  
  2433. The DTA-buffer is usually found at BASEPAGE+128 (it's always there after 
  2434. start-up), but you should not count on it. Use FGETDTA() to find the 
  2435. current address, before FSFIRST :
  2436.      dta.adr%=FGETDTA()
  2437.      e%=FSFIRST(format$,attr)
  2438. FSFIRST returns -33 if no file has been found. FSNEXT returns -49 if no 
  2439. more files are found.
  2440.  
  2441. In an accessory it's safer to create a new DTA-buffer :
  2442.      old.dta%=FGETDTA()            ! old buffer
  2443.      dta$=STRING$(44,0)
  2444.      dta.adr%=V:dta$               
  2445.      ~FSETDTA(dta.adr%)            ! new buffer
  2446.      (...)                         ! FSFIRST/FSNEXT
  2447.      ~FSETDTA(old.dta%)            ! restore old buffer
  2448. The Desktop will appreciate all this extra work.
  2449.  
  2450. The 44 byte DTA-buffer (Data Transfer Address) contains the following data 
  2451. after a succesful FSFIRST or FSNEXT :
  2452.      offset
  2453.       0-20     - reserved
  2454.         21     - attribute-byte
  2455.      22-23     - time
  2456.      24-25     - date
  2457.      26-29     - file-length
  2458.      30-43     - filename (including the extension, terminated by &H00)
  2459. The attributes and the filename can be read from the buffer with :
  2460.      attr=BYTE{dta.adr%+21}
  2461.      file$=CHAR{dta.adr%+30}
  2462.  
  2463. The DTA-buffer is not an exact copy of the relevant information in the 
  2464. directory of the disk. With a disk-editor you would find a slot of 32 
  2465. bytes for each file or folder :
  2466.      offset
  2467.       0- 7     - file- or folder-name (without extension)
  2468.       8-10     - extension
  2469.         11     - attribute-byte
  2470.      12-21     - reserved
  2471.      22-23     - time
  2472.      24-25     - date
  2473.      26-27     - FAT-pointer
  2474.      28-31     - file-length
  2475. The first byte of the filename has a special meaning in the following 
  2476. cases :   
  2477.      &H00      - free slot, never used before
  2478.      &HE5      - erased file, now free slot
  2479.      &H2E      - subdirectory 
  2480. Both time and date are stored in MS-DOS format. Consult your GFA-manual 
  2481. for more information. The FAT-pointer, also in an MS-DOS format (Intel-
  2482. format : first low byte, then high byte), points to the first cluster of 
  2483. the file. If you are looking at a folder, the FAT-pointer points to the 
  2484. cluster where you will find the directory of this folder (subdirectory). 
  2485. If you are looking at a subdirectory (i.e. you are in a folder), the first 
  2486. two slots are reserved for the files '.' and '..' (&H2E and &H2E2E). This 
  2487. has already been mentioned in the paragraph 'DIR and FILES'. Finally, the 
  2488. file-length is stored in, you guessed it, MS-DOS format. You might wonder 
  2489. what MS-DOS has to do with Atari-disks. Read the paragraphs 'Disk Format' 
  2490. and 'File Allocation Table' for the explanation.
  2491.  
  2492. If you use the attribute-byte &X10000 you will find both folders and 
  2493. files! If the folders in a directory don't have an extension and all files 
  2494. do have an extension, you could find all folders in the main directory as 
  2495. follows :
  2496.      e%=FSFIRST("\*",&X10000)      ! and e%=FSNEXT() for next folders
  2497.  
  2498. If you can't use this simple method, you'll have to check after each 
  2499. successful FSFIRST/FSNEXT if it's a folder or a file :
  2500.      IF BTST(BYTE{dta.adr%+21},4)
  2501.        (...)                       ! yes, it's a folder
  2502.      ENDIF
  2503.  
  2504. Use the attribute-byte 0 (i.e. no bits set) to find ordinary files only.
  2505.  
  2506. Use attribute-byte &X1000 to find the disk-name :
  2507.      dta.adr%=FGETDTA()
  2508.      e%=FSFIRST("\*.*",&X1000)     ! finds disk-name only, not files
  2509.      disk.name$=CHAR{dta.adr%+30}
  2510.  
  2511. You can read the attributes of a file or folder with GEMDOS 67 (Fattrib) :
  2512.      attr%=GEMDOS(67,L:V:filename$,0,0) 
  2513. If the file (or folder) is not found, attr% is -33 (or -34), otherwise 
  2514. attr% contains the attributes in the usual format. You can even change the 
  2515. attributes of files with :
  2516.      r%=GEMDOS(67,L:V:filename$,1,attribute%)
  2517. It's not possible to change the attributes of folders or the disk-name 
  2518. with GEMDOS 67. One way to do that is to change the directory-sector with 
  2519. the aid of BIOS 4 (Rwabs). If you really feel the urge to experiment, you 
  2520. should realize that one tiny mistake could ruin the disk.
  2521.  
  2522.  
  2523. EXIST
  2524.  
  2525. You can use EXIST to test if a folder exists, but only if the folder 
  2526. contains at least one file :
  2527.      IF EXIST("\FOLDER\*.*")
  2528.        (...)                  ! folder found
  2529.      ELSE
  2530.        (...)                  ! folder not found or empty folder
  2531.      ENDIF
  2532.  
  2533.        
  2534. LOF
  2535.  
  2536. The length of a file is easily determined with LOF :
  2537.      OPEN "I",#1,file$
  2538.      length%=LOF(#1)
  2539.      CLOSE #1
  2540.  
  2541. To determine the number of records in a random file you could divide the 
  2542. file-length by the total FIELD-length.
  2543.  
  2544.  
  2545. TOUCH
  2546.  
  2547. Use this method with TOUCH :
  2548.      OPEN "U",#1,file$
  2549.      TOUCH #1
  2550.      CLOSE #1
  2551.  
  2552.  
  2553. NAME
  2554.  
  2555. With the old TOS you can only change the name of files, not of folders. 
  2556. Even from the desktop you can't change the name of a folder, so choose it 
  2557. carefully.
  2558.  
  2559.  
  2560. KILL
  2561.  
  2562. KILLing a file does not erase it from the disk. The first byte of the 
  2563. filename is changed to &HE5. Unfortunately you can't restore a killed file 
  2564. by simply changing this byte with a disk-editor. The operating system will 
  2565. be able to find the first cluster of the restored file, because the first 
  2566. FAT-pointer is located in the directory. The next clusters can only be 
  2567. found through the FAT (File Allocation Table), but after KILL all pointers 
  2568. to this file are irreversibly erased. If you have not killed any file on 
  2569. the disk before your fatal mistake, you are extremely lucky and will find 
  2570. all clusters have been stored consecutively. But after some killing and 
  2571. saving on the disk, the file could be dispersed over the entire disk. Some 
  2572. programs are able to help you, but you will have to recognize clusters as 
  2573. belonging to the killed file. That's easy with ASCII-files, but almost 
  2574. impossible with other files. So, don't KILL unless you have to.  
  2575.  
  2576.  
  2577. File Copy 
  2578.  
  2579. You can copy a file source$ to dest$ (use complete pathnames!) with :
  2580.      PROCEDURE file.copy(source$,dest$)
  2581.        LOCAL block%
  2582.        OPEN "I",#90,source$
  2583.        OPEN "O",#91,dest$
  2584.        block%=LOF(#90)
  2585.        WHILE block%>32000
  2586.          PRINT #91,INPUT$(32000,#90);
  2587.          SUB block%,32000
  2588.        WEND
  2589.        PRINT #91,INPUT$(block%,#90);
  2590.        CLOSE #90
  2591.        CLOSE #91
  2592.      RETURN
  2593.  
  2594. Do not copy a file "to itself" on a harddisk. Thanks to yet another bug in 
  2595. TOS, this action could completely wipe out the harddisk. Or perhaps this 
  2596. should be called a feature of TOS, put there to punish the crazy user who
  2597. tries to copy a file to itself.
  2598.  
  2599.  
  2600. Disk Format
  2601.  
  2602. A disk contains 80 concentric tracks (numbered 0 - 79) or more. Sometimes 
  2603. the expression "cylinder" is used instead of "track". Each track is 
  2604. divided into 9, 10 or even 11 sectors. One sector can contain 512 data-
  2605. bytes. In order to be compatible with MS-DOS, TOS formats a disk with 80 
  2606. tracks and 9 sectors/track. Actually it's easy to fit 10 sectors in one 
  2607. track. With a little more effort you can create room for 11 sectors, but 
  2608. some drives run slightly too fast and are not able to read the 11th 
  2609. sector! 
  2610.  
  2611. With a disk-editor you can examine the 512 data-bytes of a sector, but 
  2612. you can't examine the sector-layout without accessing the Floppy Disk 
  2613. Controller (FDC) directly. In that case you would find the following 
  2614. layout for each sector :
  2615.      data-separator (GAP)     - 15 bytes
  2616.      ID-Address mark          - 1 byte
  2617.      sector-header            - 4 bytes (track, side, sector, size)
  2618.      CRC of sector header     - 2 bytes
  2619.      data separator           - 37 bytes
  2620.      Data-Address Mark        - 1 byte
  2621.      data bytes               - 512 bytes
  2622.      CRC of data bytes        - 2 bytes
  2623.      data separator           - 40 bytes
  2624. The data separator bytes are there to synchronize the FDC properly. The 
  2625. FDC recognizes the sector-header by the preceding ID-Address mark. The 
  2626. sector-header itself contains information about the current track, side 
  2627. and sector and also about the size of the data-field (usually 512 bytes).
  2628. The FDC checks both the sector-header and the data-field for corrupted 
  2629. bytes by comparing a computed "checksum" with the stored CRC-value. The 
  2630. operating system cannot read/write one byte from/to a sector, only 
  2631. complete sectors are read or written. GFA-Basic takes care of all the 
  2632. dirty work.
  2633.  
  2634. First some bad news. A CRC-error is not always recognized by the ROM of 
  2635. 520 ST's and 1040 ST's (bug in XBIOS 8, Floprd). If your palms are now 
  2636. getting sweatty, you could check your most precious disks with XBIOS 19 
  2637. (Flopver). This function checks for 'lost data, RNF- or CRC-errors'. 
  2638. Create a buffer of 1024 bytes and call XBIOS 19. A sector (512 bytes) is 
  2639. loaded from the disk in drive A or B (0 or 1) into the second part of the 
  2640. buffer and checked. If a bad sector is found, the sector-number is stored 
  2641. as a word in the first part of the buffer. After checking all sectors in 
  2642. one track you have to examine the word-list in the buffer. Hope you will 
  2643. find only &H0000 there. I leave the writing of this program as an exercise 
  2644. to the reader. Never thought I would use that phrase myself. Allright, 
  2645. here's something to get started :
  2646.      buffer$=STRING$(1024,0)
  2647.      adr%=V:buffer$
  2648.      r%=XBIOS(19,L:adr%,L:0,drive,1,track,side,9)  ! if 9 sectors/track
  2649. You should now be able to find out if the track on this side (0 or 1) is 
  2650. OK. Good luck.
  2651.  
  2652. You can use BIOS 7 (Getbpb) to examine the disk-format in the so-called 
  2653. BIOS-Parameter-Block (BPB) of the disk :
  2654.      bpb.adr%=BIOS(7,drive)   ! address of BPB, or 0 (= error)
  2655. In 9 words you'll find the following information in the BPB :
  2656.      offset
  2657.         0      - bytes/sector (usually 512)
  2658.         2      - sectors/cluster (usually 2) 
  2659.         4      - bytes/cluster
  2660.         6      - number of directory-sectors
  2661.         8      - length of FAT
  2662.        10      - first sector of second FAT
  2663.        12      - first data-sector
  2664.        14      - total clusters
  2665.        16      - flag (not used)
  2666.  
  2667. Use GEMDOS 54 (Dfree) to find out how many free clusters are available, or 
  2668. simply use DFREE if you want to know how many free bytes are available on 
  2669. a drive. Due to a bug, GEMDOS misses the last two clusters on a disk. You 
  2670. can't write to these clusters (2048 bytes down the drain...), but you can 
  2671. read these clusters if they do contain data. That would be a miracle, or 
  2672. an MS-DOS disk.
  2673.  
  2674. You'll probably use XBIOS 10 (Flopfmt) to format a disk from GFA-Basic. If 
  2675. you do, use &H0000 as the virgin-value for the first 18 sectors, and then
  2676. &HE5E5 for all data-sectors. You can use either 9 or 10 sectors/track, not 
  2677. 11. If you use 10 sectors/track, you should fill the first two tracks with 
  2678. &H0000 and fill sectors 19 and 20 with &HE5E5 afterwards (read the 
  2679. paragraph 'Sectors'). I don't recommend more than 80 tracks, certainly not 
  2680. more than 82 tracks. If XBIOS 10 returns a value other than 0, you'll find 
  2681. a list of bad sectors in the buffer you used (terminated with &H00). If 
  2682. one of the first 18 sectors is bad, you can throw the disk away. 
  2683.  
  2684. Using XBIOS 10, the interleave-factor should be 1. This means the sectors 
  2685. on a track are numbered consecutively: 1,2,3,4,etc. I don't understand 
  2686. why some programmers use another value and call it 'Fast Format'. The FDC 
  2687. needs more time to read a complete track if the interleave-factor is not 
  2688. 1. Perhaps they try to create the so-called Twisted (or Skewed) format. 
  2689. TOS loses time if the head moves to the next track. Because the Seek with 
  2690. Verify flag is set, the FDC first verifies the track-number and then reads 
  2691. the sector-number. While checking the track-number, sector 1 was passing, 
  2692. so we have to wait for one complete spin of the disk (200 ms, yawn) until 
  2693. sector 1 can be read. One solution is to clear the Seek with Verify flag, 
  2694. but that could lead to nasty problems if the head still rattles slightly 
  2695. at the time sector 1 is read. The best solution is the Twisted format 
  2696. (adopted by Atari from the Mega ST onwards). For a single-sided disk with 
  2697. 9 sectors on one track this means :
  2698.      track 0 : sector 1,2,3,4,5,6,7,8,9
  2699.      track 1 : sector 8,9,1,2,3,4,5,6,7
  2700.      track 2 : sector 6,7,8,9,1,2,3,4,5
  2701.      etc.
  2702. Now, sector 1 is encountered almost immediately after the track-number is 
  2703. verified. A 1-sector offset is not possible, but a 2-sector offset is 
  2704. enough to settle the rattling head. It is impossible to read data faster 
  2705. from a disk! But I'm afraid you can't format a Twisted disk with XBIOS 10 
  2706. if you have an old TOS. You have to use a special format-program.
  2707.  
  2708. If you format a disk from the desktop, bad clusters are flagged with a 
  2709. special value in the FAT. However, if TOS 1.4 encounters a bad sector, 
  2710. something goes wrong and the FAT is corrupted. One more reason to quit 
  2711. smoking, because smoke-particles definitely constitute a serious hazard to 
  2712. the health of your disks.
  2713.  
  2714. You can use XBIOS 18 (Protobt) to create a bootsector on the formatted 
  2715. disk. Don't worry about the media-byte (disk-type), because TOS doesn't 
  2716. use it. Do use &H1000000 to generate a random serial number, because it is 
  2717. very important that different disks have different serial numbers! Write 
  2718. the bootsector to the disk with XBIOS 9 (Flopwr), not with BIOS 4 (Rwabs):
  2719.      r%=XBIOS(9,L:buffer%,L:0,drive%,1,0,0,1)
  2720.  
  2721. Why are different serial numbers so important? If TOS suspects a disk-
  2722. swap, the serial number is read from the disk. A disk-swap can only be 
  2723. recognized if the number on the new disk is different from the old number. 
  2724. If the new disk contains the same serial number, TOS uses the FAT of the 
  2725. previous disk. Writing to a swapped disk will probably zap it, if you 
  2726. follow me. Disk-copiers copy everything, including serial numbers. Be 
  2727. careful!
  2728.  
  2729. Although it is possible to format a disk from GFA-Basic, I don't recommend 
  2730. it (now he tells us...). My favourite format is :
  2731.      80 tracks
  2732.      10 sectors/track
  2733.      Twisted format
  2734. I use TWISTER.PRG (not Public Domain, as far as I know), but you could use 
  2735. a Public Domain program like DCOPY (actually Shareware). The Desktop can't 
  2736. copy a Twisted disk, but file-copy is always possible. DCOPY copies any 
  2737. format, including Twisted format.
  2738. File Allocation Table (FAT)
  2739.  
  2740. The first sector on a disk is the boot-sector. The next five sectors are 
  2741. reserved for the FAT. And the next five for a copy of the FAT (actually 
  2742. it's the other way around). Finally, the main (or root) directory occupies 
  2743. the next 7 sectors (32 bytes for each slot). This means that the first 18 
  2744. sectors (No. 0-17) are reserved for the operating system. All other 
  2745. sectors are available for storing files.
  2746.  
  2747. The storage-unit for files is a cluster. A cluster consists of two 
  2748. consecutive sectors (1024 bytes). A file that contains only 1 byte will 
  2749. therefore still occupy 1024 bytes (1 K) on the disk. When a file is saved, 
  2750. the operating system looks for the first empty cluster, then the next, 
  2751. etc. Information about available clusters is stored in the FAT as a 
  2752. collection of pointers. Due to inefficient programming, the search for 
  2753. free clusters takes a long time. Try DFREE on a harddisk and you'll agree. 
  2754. Install a program like FATSPEED.PRG (Public Domain, by Ulrich Kuebler) to 
  2755. speed this up! 
  2756.  
  2757. The first three bytes of the FAT are not used by TOS, but are there to 
  2758. enable MS-DOS to read an ST-formatted disk. TOS writes &HF7FFFF, where the 
  2759. first byte (&HF7) is supposed to be the media-byte. Unfortunately MS-DOS 
  2760. doesn't understand this and refuses to read the directory properly. I'm 
  2761. not quite sure why, but changing the first three bytes to &H000000 seems 
  2762. to work. You could try &HF8FFFF (80 tracks, 9 sectors/track, single sided 
  2763. disk) or &HF9FFFF (double sided disk) instead. Or you could use the media-
  2764. byte at offset 21 from the bootsector. To make your MS-DOS friends 
  2765. completely happy, you should change the first three bytes of the bootsec-
  2766. tor to: &HEB3890. Sometimes (DOS 4.0 ?) you have to change the next three 
  2767. bytes as well: &H49424D (that's IBM in ASCII; please watch your language). 
  2768. Better still, let them use their own disk editor on their MS-DOS computer 
  2769. (e.g. Norton Utilities). Why should you do all the work? By the way, your 
  2770. ST should be able to use an MS-DOS disk without any modifications.
  2771.  
  2772. Each FAT-pointer consists of one and a halve byte (3 nibbles, i.e. 12 
  2773. bits). In hexadecimal notation this means three digits for one pointer. 
  2774. The first pointer (No. 0) points to cluster No. 0, the second to No. 1, 
  2775. etc. . Because the first two pointers don't count, you have to subtract 
  2776. two to find the actual cluster (pointer 2 points to cluster No. 0, etc.). 
  2777. The first cluster starts at sector No. 18 (remember, sectors 0-17 are 
  2778. reserved for bookkeeping), so you could find the first sector of a cluster 
  2779. with :
  2780.      (pointer - 2) * 2 + 18
  2781. The second sector of this cluster is of course the next one.
  2782.  
  2783. TOS reads the pointers in a peculiar (MS-DOS) way. Suppose the FAT-sector 
  2784. starts with :
  2785.      F7 FF FF 03 40 00 FF 0F 00
  2786. Without further explanation, this translates to :
  2787.      FAT-pointer 0 and 1 are ignored
  2788.      FAT-pointer 2 = &H003 (next cluster on sector 20 + 21)
  2789.      FAT-pointer 3 = &H004 (next cluster on sector 22 + 23)
  2790.      FAT-pointer 4 = &HFFF (last cluster of this file)
  2791.      FAT-pointer 5 = &H000 (free cluster)
  2792. In order to understand this, you have to consult the following table :
  2793.      &H000         : cluster still available
  2794.      &HFF1 - &HFF7 : bad cluster, never available
  2795.      &HFF8 - &HFFF : last cluster of this file (End Of File)
  2796.      &H002 - &HFF0 : pointer to next cluster
  2797. Assuming the FAT-pointer &H002 at offset 26 in the directory (you'll find 
  2798. &H0200 with a disk editor, that's Intel format with low byte first again), 
  2799. you should be able to figure out that this file will be found in sectors 
  2800. 18 through 23. Sectors 24/25 are empty, so this cluster is available for a 
  2801. new file. Any questions? The one big advantage of all this is compatibi-
  2802. lity with MS-DOS disks. With TOS 1.4 your ST-disks can be made completely 
  2803. compatible, so you don't even have to change a few bytes.
  2804.  
  2805. Right, you have just read the Fatman-book. The movie will be released 
  2806. shortly, but you can NOW buy those fabulous Fatman-shirts and fantastic 
  2807. Fatman-buttons. Call Atari for further details.
  2808.  
  2809.  
  2810. Sectors
  2811.  
  2812. There are two different methods to assign a number to a sector. The first 
  2813. one is to number the "physical" sectors in each track from 1 to 9 
  2814. (assuming 9 sectors/track). This way you could say the bootsector is 
  2815. sector 1 on track 0 (on side 0 if the disk is double sided). But GEMDOS 
  2816. doesn't care about tracks or sides, it counts "logical" sectors from 0 to 
  2817. 719 (80 tracks, 9 sectors/track, one sided disk) or from 0 to 1439 (double 
  2818. sided disk). According to GEMDOS, the bootsector is on sector 0. And on a 
  2819. double sided disk, physical sector 1 on track 0 of side 1 (the other side) 
  2820. would be sector 9.
  2821.  
  2822. With BIOS 4 (Rwabs) you can read (and write) complete logical sectors :
  2823.      buffer$=SPACE$(512)      ! 512 bytes for 1 sector
  2824.      buffer%=V:buffer$        ! address of buffer
  2825.      r%=BIOS(4,0,L:buffer%,1,sector%,drive%)      ! load the sucker
  2826. You would load the bootsector from the disk in drive A with :
  2827.      r%=BIOS(4,0,L:buffer%,1,0,0)
  2828. You can use BIOS 4 not only with floppy disks, but also with a harddisk 
  2829. or a RAM-disk. After loading a sector, you can read one byte with :
  2830.      b|=BYTE{buffer%+n}       ! n from 0 to 511
  2831. You can read a word with :
  2832.      w=WORD{buffer%+n}
  2833. But only if the word starts at an even address. Otherwise you have to use: 
  2834.      w=BYTE{buffer%+n+1}+256*BYTE{buffer%+n}
  2835. If necessary, you can speed this up by using the special integer commands 
  2836. for addition and multiplication. How about this Polish monster :
  2837.      DEFFN word(adr%)=ADD(BYTE{SUCC(adr%)},MUL(256,BYTE{adr%}))
  2838. Then you would use :
  2839.      w=@word(ADD(buffer%,n))     
  2840.  
  2841. If you use BIOS 4 to write a sector after formatting a disk, you should 
  2842. use '3' as a flag (not '1') :
  2843.      r%=BIOS(4,3,L:buffer%,1,sector%,drive%)
  2844.  
  2845. You can also read and write physical sectors with XBIOS 8 (Floprd) and 
  2846. XBIOS 9 (Flopwr). With these commands you could even read/write all 
  2847. sectors on one track. This is the only way to read a track, because 
  2848. reading a complete track is impossible due to a bug in the FDC.
  2849.  
  2850. If you swap a disk after loading/writing a sector you should be careful. 
  2851. Testing with BIOS 9 (Mediach) you could miss the disk-swap. This could be 
  2852. fatal, because TOS uses the FAT of the other disk! I think you could use 
  2853. BIOS 7 (Getbpb) in most cases, but use the Procedure Force.mediach if in 
  2854. doubt :
  2855.      PROCEDURE force.mediach
  2856.        LOCAL x$,old.vector%,a%
  2857.        x$=SPACE$(12)
  2858.        old.vector%=LPEEK(&H47E)
  2859.        a%=V:x$
  2860.        DPOKE a%,&H2B7C
  2861.        LPOKE a%+2,old.vector%
  2862.        DPOKE a%+6,&H47E
  2863.        DPOKE a%+8,&H7002
  2864.        DPOKE a%+10,&H4E75
  2865.        SLPOKE &H47E,a%
  2866.        ~DFREE(0)              ! current drive
  2867.      RETURN
  2868. To be more precise, BIOS 7 can't be used in the following situation :
  2869.      - TOS reads a sector
  2870.      - you swap disks
  2871.      - you use BIOS 7 in your program
  2872.      - TOS reads a sector
  2873. Now TOS will assume there has been no disk-swap, because there has been no 
  2874. disk-swap after the last BIOS 7 call! You definitely need the Procedure 
  2875. Force.mediach in this case.
  2876.  
  2877. By the track, TOS also ignores disk-swaps during a screendump (HARDCOPY), 
  2878. or while using DMA (harddisk, laser printer). TOS detects a disk-swap by 
  2879. monitoring the write-protect state. To see this, you should turn all 
  2880. lights off and then watch the drive-light closely. Closer. You can turn 
  2881. the lights on again. If the drive is empty, TOS gets a write-protect 
  2882. signal and assumes the user might have swapped disks. BIOS 9 should return 
  2883. '1' at this point. TOS checks if you really did swap disks by reading the 
  2884. serial number from the bootsector and comparing it with the current 
  2885. number. Only if these numbers are different, a disk-swap is recognized by 
  2886. TOS (BIOS 9 should return '2' now). You probably deduced that TOS will 
  2887. read the bootsector also if you use a write-protected disk. Continuously 
  2888. reading the bootsector is a waste of time, so TOS waits 1.5 seconds before 
  2889. looking again. Never swap disks within 1.5 seconds after a read/write-
  2890. operation. The drive keeps spinning for 2 seconds, so you can't go wrong 
  2891. if you wait until the drive-light is off before swapping disks.
  2892.  
  2893. Bootsector
  2894.  
  2895. In the following table you'll find the lay-out of a bootsector. All words 
  2896. are in Intel-format, except CHKSUM.
  2897.  
  2898.      offset    length    name
  2899.  
  2900.         0        2                 &H6038 = branch to bootroutine
  2901.         2        6       FILLER    fill-bytes
  2902.         8        3       SERIAL    serial-number of disk
  2903.  
  2904.        11        2       BPS       bytes/sector (512)
  2905.        13        1       SPC       sectors/cluster (2)
  2906.        14        2       RES       reserved sectors (1, Bootsector)
  2907.        16        1       NFATS     number of FAT's (2)
  2908.        17        2       NDIRS     max. entries in main directory
  2909.        19        2       NSECTS    total sectors
  2910.        21        1       MEDIA     media-byte (not used by TOS)
  2911.        22        2       SPF       sectors/FAT (5)
  2912.        24        2       SPT       sectors/track
  2913.        26        2       NSIDES    sides (1 or 2; no joke this time)
  2914.        28        2       NHID      hidden sectors (ignored by TOS)
  2915.  
  2916.        30        2       EXECFLAG  start of bootcode : flag
  2917.        32        2       LDMODE    0=load FNAME; <>0=load sectors
  2918.        34        2       SSECT     first sector (LDMODE<>0)
  2919.        36        2       SECTCNT   number of sectors
  2920.        38        4       LDADDR    load at this RAM-address
  2921.        42        4       FATBUF    address of FAT-buffer
  2922.        46       11       FNAME     filename (nnnnnnnneee) (LDMODE=0)
  2923.        57        1       DUMMY     fill-byte
  2924.  
  2925.        58                          boot-routine (could be a boot-virus)
  2926.  
  2927.       510        2       CHKSUM    
  2928.  
  2929. TOS determines if the bootsector is executable by adding all bytes. If 
  2930. this sum (AND &HFFFF) equals &H1234, the bootsector is executable. If you 
  2931. use GFA-Basic this probably means you have an ancient ST with TOS in RAM, 
  2932. or a boot-virus. A normal GFA-disk has only &H00- or &HE5-bytes from the 
  2933. offset 58.  
  2934.  
  2935.  
  2936. BLOAD
  2937.  
  2938. BLOAD needs an address, unless you have used BSAVE in the same program 
  2939. before. In that case the BSAVE-address is used automatically by BLOAD if 
  2940. you don't specify a new address.
  2941.  
  2942. BLOAD (BSAVE) is easier to use than BGET (BPUT), because you don't have to 
  2943. open the file. But with BLOAD you can only load the entire file, while 
  2944. BGET allows you to load any part of the file.
  2945.  
  2946.  
  2947. INP and OUT
  2948.  
  2949. Both INP and OUT can also be used with 2-byte and 4-byte integers :
  2950.      a|=INP(#n)
  2951.      a&=INP&(#n)
  2952.      a%=INP%(#n)
  2953.      OUT #n,a|
  2954.      OUT& #n,a&
  2955.      OUT% #n,a%
  2956.  
  2957.  
  2958. INPUT and LINE INPUT
  2959.  
  2960. Because GFA now uses a 4K-buffer for each opened file (version 3.07), 
  2961. reading data from a file with (LINE) INPUT goes much faster.
  2962.  
  2963.  
  2964. STORE and RECALL
  2965.  
  2966. For very fast loading and saving of string-arrays, you should use RECALL 
  2967. and STORE. You can also store (or recall) a part of an array as follows :
  2968.      STORE #1,txt$(),10       ! store elements 0 through 9
  2969.      STORE #1,txt$(),5 TO 10  ! store elements 5 through 10
  2970.  
  2971. The correct syntax is :
  2972.      STORE #i,x$()[,n[ TO m]]
  2973.      RECALL #i,x$(),n[ TO m],x%    (use n=-1 for complete array)
  2974. Of course you have to open the file first.
  2975.  
  2976. If you STORE a text-array, GFA puts &H0D0A (CHR$(13);CHR$(10)) after each 
  2977. element. This is the same format as used by 1st Word Plus (WP Mode off, 
  2978. i.e. ASCII-mode), Tempus, etc.
  2979.  
  2980. If you're going to show more than a few text-lines, you could enter the 
  2981. text as DATA-lines, e.g. with the Procedures Initio.text.array and 
  2982. Initio.text.array.low (for Low resolution) : 
  2983.      PROCEDURE initio.text.array
  2984.        ' *** global :  TEXT$()
  2985.        LOCAL lines,line$,n
  2986.        lines=0
  2987.        RESTORE txt.data
  2988.        READ line$
  2989.        REPEAT
  2990.          INC lines
  2991.        READ line$
  2992.        UNTIL line$="***"
  2993.        ERASE text$()
  2994.        DIM text$(lines)
  2995.        RESTORE txt.data
  2996.        FOR n=1 TO lines
  2997.          READ text$
  2998.          text$(n)=SPACE$(5)+text$           ! left margin of 5 spaces !!
  2999.        NEXT n
  3000.        txt.data:
  3001.        DATA text
  3002.        DATA ***
  3003.      RETURN
  3004.  
  3005. If you are going to show more text, I suggest you use 1st Word Plus, or 
  3006. any other wordprocessor or text-editor that can save your text as an 
  3007. ASCII-file. With 1st Word Plus, I use a Ruler length of 70 and the 
  3008. following Page Layout Form :
  3009.      Paper length   66
  3010.      TOF margin     19
  3011.      Head margin     4
  3012.      Foot margin     4
  3013.      BOF margin     19
  3014.      Lines/page     20
  3015. Enter the text and save as an ASCII-file (turn WP Mode off before saving). 
  3016. In your GFA-Basic program you would first load the text in a string-array:
  3017.      DIM text$(lines)
  3018.      OPEN "I",#1,file$
  3019.      RECALL #1,text$(),-1,lines%   ! lines% ≤ lines+1
  3020.      CLOSE #1
  3021. Then you could use the Procedure Show.text.page (High or Medium resolu-
  3022. tion) to show the text with 20 lines/screen. The Procedure uses a left and 
  3023. right margin of 5 characters, so that's why you have to use 70 charac-
  3024. ters/line in your wordprocessor. If the text-array is full, you won't get 
  3025. an error if the file contains more text-lines! 
  3026.  
  3027. You could use a 2-dimensional string-array to store first and last names :
  3028.      name$(i,0)=first_name$
  3029.      name$(i,1)=last_name$
  3030. Again, STORE and RECALL are very fast. But it is now necessary to use 
  3031. exactly the same dimensions with RECALL that you used with STORE. If the 
  3032. dimensions don't match, the array will be scrambled after RECALL.
  3033.  
  3034.  
  3035. FILESELECT
  3036.  
  3037. Don't use the underscore '_' in the path-line of the Fileselector, because 
  3038. a bug in the old TOS will then cause a few bombs. Owners of a Mega ST or 
  3039. TOS-version 1.4 can use as many underscores as they like.
  3040.  
  3041. Changing drives in the Fileselector (old TOS) is not easy. Click on the 
  3042. path-line and press <Esc> to clear the line. Enter the drive, e.g. 'D:\', 
  3043. and click on the bar under the path-line in order to read the new 
  3044. directory. Also click on this bar after changing disks (in this case you 
  3045. would press <Esc> on the desktop). Selecting drive A is easier: just clear 
  3046. the path-line and click on the bar. The TOS-code that takes care of all 
  3047. this work is also known as the bartender.
  3048.  
  3049. If you have changed the extension in the path-line, you should click just 
  3050. below the bar. If you click on the bar, the path-line is overwritten with 
  3051. '*.*' ! That same bartender strikes again.
  3052.  
  3053. The correct syntax for calling the Fileselector is :
  3054.      FILESELECT [#title$,]path$,default$,file$
  3055. The title is only used in TOS-version 1.4 and ignored in older TOS-
  3056. versions. The default$ usually is the null-string (""), but don't use the 
  3057. null-string for path$ or the Fileselector will freeze. Use "\*.*" as path$ 
  3058. for all files in the main directory. Do use the backslash in the pathname 
  3059. (e.g. "A:\*.*"). Due to a bug in GEM, the wrong drive is sometimes used if 
  3060. you forget the backslash ("A:*.*"). If the user has selected a file, file$ 
  3061. will contain the path and filename. The file$ will be the null-string if 
  3062. the user selected <Cancel>. A third possibility is easily overlooked: the 
  3063. user could have selected <OK> without choosing a file. In that case file$ 
  3064. contains the current path, ending with a backslash.
  3065.  
  3066. Do not despair if you need a title, but don't have TOS 1.4. Try the 
  3067. Procedure Fileselect (High or Medium resolution) or Fileselect.low : 
  3068.      PROCEDURE fileselect(path$,default$,txt$,left$,right$,VAR file$)
  3069.        ' *** print optional title (light text) to left and right 
  3070.        LOCAL screen$,y.fac
  3071.        SGET screen$          
  3072.        CLS
  3073.        IF high.res!
  3074.          y.fac=1
  3075.        ELSE
  3076.          y.fac=2
  3077.        ENDIF
  3078.        DEFTEXT black,2,900,32
  3079.        TEXT 100,350/y.fac,300/y.fac,left$
  3080.        DEFTEXT ,,2700
  3081.        TEXT 540,50/y.fac,300/y.fac,right$
  3082.        DEFTEXT ,0,0,13
  3083.        PRINT AT(1,3);@center$(txt$)
  3084.        GRAPHMODE 3
  3085.        DEFFILL black,1 
  3086.        BOUNDARY 0
  3087.        IF high.res!
  3088.          BOX 157,25,482,54
  3089.          PLOT 157,25
  3090.          PBOX 159,27,480,52
  3091.        ELSE
  3092.          BOX 157,12,482,27
  3093.          PLOT 157,12
  3094.          PBOX 160,14,479,24
  3095.        ENDIF
  3096.        BOUNDARY 1
  3097.        GRAPHMODE 1
  3098.        FILESELECT path$,default$,file$
  3099.        SPUT screen$
  3100.      RETURN
  3101. As a programmer, you should take into account the possibility that a user 
  3102. might start your program from drive A, a harddisk or a RAM-disk. I use the 
  3103. Standard Global default.path$ to remember where the program was started. 
  3104. If the user changes the (default) path in the Fileselector, you should 
  3105. note the change and use the new path if the Fileselector is called again. 
  3106. Use the Procedure Parse.filename for this purpose :
  3107.      PROCEDURE parse.filename(parse.name$,VAR drive$,path$,file$,ext$)
  3108.        LOCAL pos,first,last,last!,search,parse.file$
  3109.        '
  3110.        parse.name$=UPPER$(parse.name$)
  3111.        IF MID$(parse.name$,2,1)=":"
  3112.          drive$=LEFT$(parse.name$,1)
  3113.        ELSE
  3114.          drive$=CHR$(65+GEMDOS(&H19))    ! current drive
  3115.        ENDIF
  3116.        '
  3117.        pos=1
  3118.        last!=FALSE
  3119.        last=0
  3120.        first=INSTR(1,parse.name$,"\")
  3121.        REPEAT
  3122.          search=INSTR(pos,parse.name$,"\")
  3123.          IF search>0
  3124.            pos=search+1
  3125.            last=search
  3126.          ELSE
  3127.            last!=TRUE
  3128.          ENDIF
  3129.        UNTIL last!
  3130.        IF last>0                              ! backslash discovered
  3131.          path$=MID$(parse.name$,first,last-first+1)
  3132.          parse.file$=MID$(parse.name$,last+1)
  3133.        ELSE                                   ! no '\'
  3134.          path$=""
  3135.          pos=INSTR(1,parse.name$,":")
  3136.          IF pos>0
  3137.            parse.file$=MID$(parse.name$,pos+1)
  3138.          ELSE
  3139.            parse.file$=parse.name$
  3140.          ENDIF
  3141.        ENDIF
  3142.        pos=INSTR(parse.file$,".")
  3143.        IF pos>0                               ! name with extension
  3144.          ext$=MID$(parse.file$,pos+1)
  3145.          file$=LEFT$(parse.file$,pos-1)
  3146.        ELSE                                   ! name without extension
  3147.          ext$=""
  3148.          file$=parse.file$
  3149.        ENDIF
  3150.      RETURN
  3151.  
  3152. If you have a joystick with Auto-Fire on, you should switch it off. The 
  3153. Fileselector doesn't like Auto-Fire. Neither do I. 
  3154.  
  3155. The Fileselector will warn you with a modest 'ping' if it counts more than 
  3156. 100 files/folders. It will show only the first 100 files/folders. I think 
  3157. 45 files in one folder is really the limit for impatient users like 
  3158. myself. More than 100 is a crime that should be punished with more than a 
  3159. 'ping'. The main directory of drive A can't contain more than 112 
  3160. files/folders, because the 7 directory-sectors contain 112 32-byte slots.
  3161.  
  3162. Every time you open a folder (in the Fileselector, or otherwise), TOS 
  3163. stores information about the folder in a table. After opening/accessing 40 
  3164. folders, TOS will delete clusters, cross-link clusters, and do other nasty 
  3165. things. Your disk could be completely destroyed, thanks to this bug. Atari 
  3166. enlarged the buffer in TOS 1.2 and fixed the bug in TOS 1.4. Atari also 
  3167. distributes the program FOLDRxxx.PRG to extend the 40-folder limit with 
  3168. 100 (FOLDR100.PRG) or more. Be careful with SHOW INFO, it's easy to exceed 
  3169. the 40-folder limit! You could recognize a disaster by one of the 
  3170. following symptoms :
  3171.      - unexpected '0 bytes in 0 items' message in directory
  3172.      - folder-names trashed (usually lots of Greek letters)
  3173.      - Show Info crashes or shows weird information
  3174. Don't be afraid of a new virus. It's only a TOS-bug. Immediately reset 
  3175. your ST, try to salvage as many files as possible and reformat the disk. 
  3176. If all files are lost, you will have to use your back-up files. If you 
  3177. don't have back-up files, you have nothing left but my sympathy. 
  3178.  
  3179.  
  3180.                                 12.  MIDI
  3181.  
  3182.  
  3183. INPMID$
  3184.  
  3185. With the command INPMID$ the internal Midi-buffer is read and at the same 
  3186. time cleared. You can find the buffer with XBIOS 14 (Iorec) :
  3187.      adr%=LPEEK(XBIOS(14,2))
  3188. The default size of this buffer is only 128 bytes, but you can use the 
  3189. Procedure Change.midi.buffer to change the size of the buffer :
  3190.      PROCEDURE change.midi.buffer(size%)
  3191.        LOCAL ptr%
  3192.        ptr%=XBIOS(14,2)
  3193.        ERASE buffer|()
  3194.        DIM buffer|(size%-1)
  3195.        LPOKE ptr%,VARPTR(buffer|(0))   ! start-address of new buffer
  3196.        DPOKE ptr%+4,size%              ! size
  3197.        DPOKE ptr%+6,0                  ! buffer-head
  3198.        DPOKE ptr%+8,0                  ! buffer-tail
  3199.        DPOKE ptr%+10,0                 ! low mark (not used)
  3200.        DPOKE ptr%+12,size%-1           ! high mark (not used)
  3201.      RETURN
  3202. Because handshake is impossible with Midi, you need a large buffer if 
  3203. Midi-bytes are coming in fast.
  3204.  
  3205.  
  3206. INP
  3207.  
  3208. If you use INP(3) to read Midi-bytes, you should first check with INP?(3) 
  3209. if the Midi-buffer contains data. If you use INP(3) and no bytes are 
  3210. available, your ST will freeze. Until you reset the computer.
  3211.  
  3212.  
  3213. Midi-commands
  3214.  
  3215. Study the Procedures in the file MIDI.LST to see how you can use Midi-
  3216. commands in GFA-Basic. With the Procedures Record.midi and Play.midi you 
  3217. could write a simple Midi-recorder. And the Procedure Midi.monitor can be 
  3218. used to examine incoming Midi-messages.
  3219.      PROCEDURE record.midi(VAR midi.byte|(),midi.time%())
  3220.        ' *** uses Procedure All.midi.off
  3221.        ' *** global :  LAST.MIDI.BYTE%
  3222.        LOCAL last%,buffer$,i%,t%,time%,byte|,delay%,j%,m$,k
  3223.        ARRAYFILL midi.byte|(),0
  3224.        ARRAYFILL midi.time%(),0
  3225.        last%=DIM?(midi.byte|())-1
  3226.        m$=STR$(last%)+" bytes available ;| |stop recording|"
  3227.        m$=m$+"by pressing space"
  3228.        ALERT 3,m$,1,"RECORD",k
  3229.        REPEAT
  3230.        UNTIL INKEY$=""
  3231.        buffer$=INPMID$         ! clear MIDI-buffer
  3232.        i%=1
  3233.        t%=TIMER
  3234.        REPEAT
  3235.          IF INP?(3)
  3236.            byte|=INP(3)
  3237.            IF byte|<>254
  3238.              time%=SUB(TIMER,t%)
  3239.              midi.byte|(i%)=byte|
  3240.              midi.time%(i%)=time%
  3241.              INC i%
  3242.            ENDIF
  3243.          ENDIF
  3244.        UNTIL i%=last% OR INKEY$=" "
  3245.        last.midi.byte%=i%-1
  3246.        @all.midi.off
  3247.        delay%=midi.time%(1)               ! subtract time for first note
  3248.        FOR j%=1 TO i%
  3249.          SUB midi.time%(j%),delay%
  3250.        NEXT j%
  3251.        m$="|"+STR$(i%)+" bytes recorded"
  3252.        ALERT 3,m$,1," OK ",k
  3253.      RETURN
  3254.      '
  3255.      PROCEDURE play.midi(VAR midi.byte|(),midi.time%())
  3256.        ' *** uses Procedure All.midi.off
  3257.        LOCAL m$,k,i%,t%,time%
  3258.        m$="record of "+STR$(INT(midi.time%(last.midi.byte%)/200))+
  3259.        m$=m$+" seconds| |(stop by pressing space)"
  3260.        ALERT 3,m$,1,"PLAY",k
  3261.        REPEAT
  3262.        UNTIL INKEY$=""
  3263.        i%=1
  3264.        t%=TIMER
  3265.        REPEAT
  3266.          time%=SUB(TIMER,t%)
  3267.          IF midi.time%(i%)<=time%
  3268.            OUT 3,midi.byte|(i%)
  3269.            INC i%
  3270.          ENDIF
  3271.        UNTIL i%=last.midi.byte% OR INKEY$=" "
  3272.        @all.midi.off
  3273.      RETURN
  3274.      '
  3275.      PROCEDURE midi.monitor
  3276.        LOCAL m$,k,byte|,byte$,hex$,bin$,buffer$,key$
  3277.        byte$=SPACE$(3)
  3278.        hex$=SPACE$(2)
  3279.        bin$=SPACE$(8)
  3280.        m$="all incoming bytes|(except 254) are|printed on screen ;|"
  3281.        m$=m$+"stop by pressing space"
  3282.        ALERT 1,m$,1,"START",k
  3283.        m$="press|<Return>|for CLS"
  3284.        ALERT 1,m$,1," OK ",k
  3285.        REPEAT
  3286.        UNTIL INKEY$=""
  3287.        buffer$=INPMID$      ! clear MIDI-buffer
  3288.        CLS
  3289.        PRINT TAB(10);"dec";TAB(20);"hex";TAB(30);"binary"
  3290.        REPEAT
  3291.           REPEAT
  3292.            key$=INKEY$
  3293.            IF INP?(3)
  3294.              byte|=INP(3)
  3295.              IF byte|<>254
  3296.                IF TIMER-t%>200
  3297.                  PRINT
  3298.                ENDIF
  3299.                t%=TIMER
  3300.                RSET byte$=STR$(byte|)
  3301.                RSET hex$=HEX$(byte|)
  3302.                RSET bin$=BIN$(byte|)
  3303.                PRINT TAB(10);byte$;TAB(20);hex$;TAB(30);bin$
  3304.              ENDIF
  3305.            ENDIF
  3306.          UNTIL key$=" " OR key$=CHR$(13)
  3307.          IF key$=CHR$(13)
  3308.            CLS
  3309.          ENDIF
  3310.        UNTIL key$=" "
  3311.        @all.midi.off
  3312.        REPEAT
  3313.        UNTIL INKEY$=""
  3314.        PRINT " (press any key)"
  3315.        ~INP(2)
  3316.      RETURN
  3317.  
  3318.  
  3319.                                 13.  MODEM
  3320.  
  3321.  
  3322. INPAUX$
  3323.  
  3324. With the command INPAUX$ the internal RS232-buffer is read and at the same 
  3325. time cleared. You can find the address of the input-buffer with :
  3326.      adr.in%=LPEEK(XBIOS(14,0))
  3327. The output-buffer can be located with :
  3328.      adr.out%=LPEEK(XBIOS(14,0)+14)
  3329.  
  3330.  
  3331. INP
  3332.  
  3333. If you use INP(1) to read incoming bytes, you should always check with 
  3334. INP?(1) if the RS232-buffer contains data. 
  3335.  
  3336.  
  3337. Rsconf (XBIOS 15)
  3338.  
  3339. With XBIOS 15 (Rsconf) you can change the RS232-parameters. A few 
  3340. baudrates :
  3341.      0 - 19200 baud
  3342.      1 -  9600 baud
  3343.      4 -  2400 baud
  3344.      7 -  1200 baud
  3345.      9 -   300 baud
  3346.     14 -    75 baud
  3347. Use -1 for parameters you don't want to change. Due to a TOS-bug, you 
  3348. can't use 75 baud, because '14' results in 120 baud. Also, the old TOS 
  3349. (pre-Blitter age) can't handle hardware handshake with RTS/CTS-signals. 
  3350. Atari has released a bug-fix that should enable any TOS to use RTS/CTS. 
  3351. Software handshaking (XON/XOFF) functions properly. The default 
  3352. after power-up is no handshake protocol.
  3353.  
  3354.  
  3355.                                 14.  MOUSE
  3356.  
  3357.  
  3358. Editor
  3359.  
  3360. Sometimes the editor seems to freeze while the cursor is blinking rapidly. 
  3361. Just move the mouse and the editor comes alive again.
  3362.  
  3363.  
  3364. Fileselector
  3365.  
  3366. Sometimes the same blinking mouse appears after calling the Fileselector 
  3367. or an Alert-box. I've read somewhere this could be due to the combination 
  3368. of a VDI-function (for the mouse) and an AES-function (for Fileselector or 
  3369. Alert-box). GFA takes care of the first and GEM of the second, and 
  3370. sometimes this seems to result in a conflict.
  3371.  
  3372.  
  3373. MOUSE
  3374.  
  3375. If you repeatedly call a Procedure in which you test for a mouse-click, 
  3376. you should incorporate a short pause in the Procedure (e.g. PAUSE 5). 
  3377. Otherwise the Procedure might be called again while the user is still 
  3378. holding the button down. You could also wait until the user releases the 
  3379. button :
  3380.      REPEAT
  3381.      UNTIL MOUSEK=0      ! wait until button is released
  3382.  
  3383. If you find it difficult to move the mouse accurately, you could use 
  3384. <Shift> <Alternate> <arrow> to move the mouse-cursor one pixel in the 
  3385. desired direction. If you press <Insert> as well, you can "drag" something 
  3386. accurately as if the left mouse-button was pressed.
  3387.  
  3388. You can find the maximal x- and y-coordinates of the mouse with :
  3389.      x=DPEEK(&H9862)
  3390.      y=DPEEK(&H9864)
  3391. But there's no guaranty you will find the coordinates there. Experiment 
  3392. with XBIOS 0 for a more reliable method. Don't ask me how.
  3393.  
  3394. MOUSE returns negative coordinates if the mouse is to the left of or above 
  3395. the current window (or the origin that has been selected with CLIP 
  3396. OFFSET).
  3397.  
  3398.  
  3399. SETMOUSE
  3400.  
  3401. A mouseclick can be simulated with :
  3402.      SETMOUSE mx,my,mk
  3403. If you try this with an Alert-button you have to move the mouse after-
  3404. wards, or the button won't be selected. I don't know why, so I can't tell 
  3405. if this is a bug.
  3406.  
  3407.  
  3408. DEFMOUSE
  3409.  
  3410. You can use one of the many Public Domain mouse-editors to design your own 
  3411. mouse-mutant. But it's also easy to create a new mouse-cursor with the 
  3412. Procedure Initio.mouse1 :
  3413.      PROCEDURE initio.mouse1
  3414.        ' *** global :  MOUSE1$
  3415.        RESTORE pattern.mouse1
  3416.        @make.mouse(mouse1$)
  3417.        pattern.mouse1:
  3418.        ' *** x,y,mode(0=normal;1=XOR),mask-colour,mouse-colour
  3419.        DATA 0,0,0,0,1
  3420.        ' *** mask-pattern (1 = pixel on , 0 = pixel off)
  3421.        DATA 0000000000000000
  3422.        DATA 0000000000000000
  3423.        DATA 0000000000000000
  3424.        DATA 0000000000000000
  3425.        DATA 0000000000000000
  3426.        DATA 0000000000000000
  3427.        DATA 0000000000000000
  3428.        DATA 0000000000000000
  3429.        DATA 0000000000000000
  3430.        DATA 0000000000000000
  3431.        DATA 0000000000000000
  3432.        DATA 0000000000000000
  3433.        DATA 0000000000000000
  3434.        DATA 0000000000000000
  3435.        DATA 0000000000000000
  3436.        DATA 0000000000000000
  3437.        ' *** mouse-pattern
  3438.        DATA 0000000000000000
  3439.        DATA 0000000000000000
  3440.        DATA 0000000000000000
  3441.        DATA 0000000000000000
  3442.        DATA 0000000000000000
  3443.        DATA 0000000000000000
  3444.        DATA 0000000000000000
  3445.        DATA 0000000000000000
  3446.        DATA 0000000000000000
  3447.        DATA 0000000000000000
  3448.        DATA 0000000000000000
  3449.        DATA 0000000000000000
  3450.        DATA 0000000000000000
  3451.        DATA 0000000000000000
  3452.        DATA 0000000000000000
  3453.        DATA 0000000000000000
  3454.      RETURN
  3455.      ' 
  3456.      PROCEDURE make.mouse(VAR m$)
  3457.        LOCAL x,y,mode,msk.color,mouse.color,n,msk%,mouse%,msk.pat$
  3458.        LOCAL mouse.pat$,msk$,mouse$,pat$
  3459.        CLR msk.pat$,mouse.pat$,pat$
  3460.        READ x,y,mode,msk.color,mouse.color
  3461.        FOR n=1 TO 16
  3462.          READ msk$
  3463.          msk%=VAL("&X"+msk$)
  3464.          msk.pat$=msk.pat$+MKI$(msk%)
  3465.        NEXT n
  3466.        FOR n=1 TO 16
  3467.          READ mouse$
  3468.          LET mouse%=VAL("&X"+mouse$)
  3469.          LET mouse.pat$=mouse.pat$+MKI$(mouse%)
  3470.        NEXT n
  3471.        m$=MKI$(x)+MKI$(y)+MKI$(mode)+MKI$(color.index(msk.color))
  3472.        m$=m$+MKI$(color.index(mouse.color))+msk.pat$+mouse.pat$
  3473.      RETURN
  3474. The mask should be an exact copy of the mouse-pattern if you need a 
  3475. transparant mouse. Leave the mask empty (all '0') and the mouse will 
  3476. disappear behind objects on the screen. Fill the mask with '1' and the 
  3477. 16x16 mouse will always remain visible. Switch mask- and mouse-colour in 
  3478. the first DATA-line to create a "reverse" mouse. Or use any VDI colour-
  3479. index that is available in the current resolution.
  3480.  
  3481.  
  3482.                               15.  JOYSTICK
  3483.  
  3484.  
  3485. STRIG and STICK
  3486.  
  3487. Here is an example of the use of STRIG and STICK if your joystick is 
  3488. connected to Port 1 (your mouse is connected to Port 0) :
  3489.      STICK 1             ! joystick-mode (your mouse is now dead)
  3490.      REPEAT
  3491.        IF STRIG(1)
  3492.          joy=3
  3493.        ELSE
  3494.          joy=STICK(1)
  3495.        ENDIF
  3496.        ON joy GOSUB n,s,fire,w,nw,sw,dummy,e,ne,se
  3497.        PAUSE 5
  3498.        (...)
  3499.      UNTIL condition!
  3500.      STICK 0             ! back to mouse-mode
  3501. You need eight Procedures for the eight possible directions (see below) 
  3502. and one Procedure for the Fire-button. The value 7 ('dummy') never occurs. 
  3503. If you don't touch the joystick, the value of 'joy' will be 0, and this 
  3504. means no Procedure will be called. A short pause is advisable, because 
  3505. GFA-Basic is too fast.
  3506.                     5 1 9
  3507.                      \|/
  3508. directions :        4-0-8
  3509.                      /|\
  3510.                     6 2 10
  3511.  
  3512. If you desperately need an active mouse while using the joystick, you 
  3513. could try the following "dirty" method :
  3514.      REPEAT
  3515.        IF MOUSEK=2
  3516.          joy=3
  3517.        ELSE
  3518.          joy=BYTE{&HE09}        ! for TOS-version 1.0 !!
  3519.        ENDIF 
  3520.        ON joy GOSUB n,s,fire,w,nw,sw,dummy,e,ne,se
  3521.        PAUSE 5  
  3522.      UNTIL condition!
  3523.  
  3524.  
  3525.                                 16.  SOUND
  3526.  
  3527.  
  3528. SOUND and WAVE
  3529.  
  3530. After a SOUND-command, the sound sometimes continues in spite of the 
  3531. elapsed time. If the command is followed by another SOUND- or a WAVE-
  3532. command, the time is handled correctly. This certainly sounds like a GFA-
  3533. bug.
  3534.  
  3535. The easiest way to stop all sound is :
  3536.      WAVE 0,0       ! turn all sound off
  3537.  
  3538. Sound of a certain frequency can be produced with :
  3539.      SOUND ch,vol,#ROUND(125000/freq%),pause
  3540.  
  3541. Although our ST is not famous for its brilliant sound, you can produce 
  3542. nice sound-effects with the simple commands SOUND and WAVE. Check out the 
  3543. Procedures Siren.sound, Tideli.sound, Bounce1.sound and Bounce2.sound to 
  3544. hear what I mean.
  3545.  
  3546.  
  3547. Dosound (XBIOS 32)
  3548.  
  3549. XBIOS 32 (Dosound) can be used to play music in a special format. I 
  3550. propose to use the extension 'X32' for song-files in this format. The 
  3551. operating system takes care of playing the music during interrupts (every 
  3552. 1/50th second). Take a look at the Procedures Play.song and Stop.song to 
  3553. see how you could use XBIOS 32 in your programs. You can even play a song 
  3554. continuously with the Procedure Play.cont.song. Temporarily stopping a 
  3555. song is possible with the Procedure Interrupt.song. 
  3556.  
  3557. If you use XBIOS 32 to play music, you are advised to switch the key-click 
  3558. off. Otherwise the music will stop as soon as the user presses a key.
  3559.  
  3560. Once I discovered XBIOS 32 did not work during the initialization (mainly 
  3561. the filling of arrays) of a large program. I had converted the program 
  3562. from GFA-Basic 2.0 to 3.0, but I did not have the patience to find out 
  3563. what caused this problem.
  3564.  
  3565. XBIOS 32 can also be used for sound-effects. I have developed the 
  3566. Procedure Initio.sound for building sound-strings from a few DATA-lines.
  3567. I hereby declare this as the standard method for creating sound-strings. 
  3568. After @do.sound(sound$) you can hear the sound-effect. In the following 
  3569. example the sound-string bounce3$ is created :
  3570.      PROCEDURE initio.sound
  3571.        ' *** commands in DATA-lines :
  3572.        ' ***         REG = 14 parameters for registers 0-13
  3573.        ' ***         END = end of sound-string
  3574.        ' ***         PAUSE = pause (followed by time in 1/50 seconds)
  3575.        ' ***         VAR = decrease/increase tone : channel,start,+/-step,
  3576.        ' ***                                                     end-value
  3577.        '
  3578.        bounce3.sound:
  3579.        DATA REG,0,0,0,0,0,0,27,248,16,16,16,35,95,0
  3580.        DATA VAR,3,255,-1,116
  3581.        DATA PAUSE,255,END
  3582.        RESTORE bounce3.sound
  3583.        @sound.string(bounce3$)
  3584.      RETURN
  3585.      ' 
  3586.      PROCEDURE sound.string(VAR s$)
  3587.        LOCAL n,snd$,snd,channel,begin,step,end
  3588.        s$=""
  3589.        DO
  3590.          READ snd$
  3591.          snd$=UPPER$(snd$)
  3592.          EXIT IF snd$="END"
  3593.          IF snd$="REG"
  3594.            FOR n=0 TO 13
  3595.              READ snd
  3596.              s$=s$+CHR$(n)+CHR$(snd)
  3597.            NEXT n
  3598.          ENDIF
  3599.          IF snd$="PAUSE"
  3600.            READ snd
  3601.            s$=s$+CHR$(130)+CHR$(snd)
  3602.          ENDIF
  3603.          IF snd$="VAR"
  3604.            READ channel,begin,step,end
  3605.            s$=s$+CHR$(128)+CHR$(begin)+CHR$(129)+CHR$(channel)+CHR$(step)
  3606.            s$=s$+CHR$(end)
  3607.          ENDIF
  3608.        LOOP
  3609.        s$=s$+CHR$(255)+CHR$(0)               ! terminator
  3610.      RETURN
  3611.      ' 
  3612.      PROCEDURE do.sound(sound$)
  3613.        VOID XBIOS(32,L:VARPTR(sound$))
  3614.      RETURN
  3615.  
  3616.  
  3617. Samples
  3618.  
  3619. From GFA-Basic you can surprise the user with a sampled sound. Examine the 
  3620. Procedures Sample, Load.sample and Play.sample to see how. You'll have to 
  3621. find suitable samples first. Look out for sound-effects and speech-
  3622. samples. Personally, I just love the famous Perfect-sample.
  3623.  
  3624.  
  3625. Speech
  3626.  
  3627. Your ST can talk to you with a little help (STSPEECH.TOS). My current GFA-
  3628. version (3.07) refuses to cooperate with the Procedures Initio.speech and 
  3629. Talk, but I have included these anyway. Perhaps you can discover the bug. 
  3630. In earlier versions both Procedures did work. A reset is necessary because 
  3631. EXEC 3 is used.
  3632.  
  3633.  
  3634. Soundmachine
  3635.  
  3636. You can play songs, created with Soundmachine (TommySoftware), from GFA-
  3637. Basic. You'll need the Procedures Initio.soundmachine and Soundmachine, 
  3638. and a song-file. You'll probably wonder if it's really your ST that's 
  3639. playing the song. Soundmachine II is out, and looks even better. In this 
  3640. new version you can choose between playing songs with samples, or without 
  3641. samples (or samples for one of the three channels). You'll need the 
  3642. Procedure Sm.initio or Msm.initio and several others. Try to find the 
  3643. Public Domain demo-programs SAMSOUND.GFA, CHIPSND.GFA and SND_PLAY.GFA. 
  3644. End of commercial, continue with text. 
  3645.  
  3646.  
  3647.                           17.  PROGRAM DECISIONS
  3648.  
  3649.  
  3650. IF ... ENDIF
  3651.  
  3652. If the value of a certain variable must fall in the range min%-max%, you 
  3653. could program that as follows :
  3654.      IF n%>max%
  3655.        n%=max%
  3656.      ENDIF
  3657.      IF n%<min%
  3658.        n%=min%
  3659.      ENDIF
  3660. In this case you could also use MAX and MIN :
  3661.      n%=MAX(MIN(n%,max%),min%)
  3662.  
  3663. You probably test for two conditions by using :
  3664.      IF cond1! AND cond2!
  3665.        (...)                  ! both true
  3666.      ENDIF
  3667. But separate testing is much faster :
  3668.      IF cond1!
  3669.        IF cond2!
  3670.          (...)                ! both true
  3671.        ENDIF
  3672.      ENDIF
  3673.  
  3674.  
  3675. SELECT
  3676.  
  3677. Multiple 'ELSE IF'-constructions can be replaced by a 'SELECT'-
  3678. construction. At each CASE you can use integers, strings or integer-
  3679. variables (not string-variables). Only the first four bytes of a string 
  3680. can be used. The editor will not accept something like CASE "test2", 
  3681. only CASE "test".
  3682.  
  3683.  
  3684.  
  3685.                             18.  PROGRAM LOOPS
  3686.  
  3687.  
  3688. Calculations
  3689.  
  3690. Try to remove all unnecessary calculations from loops, e.g. :
  3691.      FOR i=1 TO 1000
  3692.        x(i)=2*q*i
  3693.      NEXT i
  3694. It's a better idea to calculate 2*q outside the loop :
  3695.      q2=q*2
  3696.      FOR i=1 TO 1000
  3697.        x(i)=q2*i
  3698.      NEXT i
  3699.  
  3700. Always try to convert floating point variables to integers before entering 
  3701. a loop. Then you will be able to use the fast integer-operators. An 
  3702. obvious example would be a calculation with dollars (24.37) that could be 
  3703. replaced by a calculation with cents (2437). Use this method if you know 
  3704. the lowest possible value of the floating point variable (0.01 in this 
  3705. case) and then divide by this value. But watch out for rounding errors and 
  3706. integer-overflow. 
  3707.  
  3708. Powers of 2 can be calculated fast by setting a bit :
  3709.      x%=BSET(0,6)   ! faster than x%=2^6
  3710. And for the ultimate speed-freaks, multiplying with a power of 2 is 
  3711. slightly faster with SHL :
  3712.      y%=SHL(x%,3)   ! faster than y%=MUL(x%,8)
  3713. Of course there is no overflow-control if you use SHL (or MUL).
  3714.  
  3715. Sometimes, calculations in a loop can be replaced by a look-up table :
  3716.      FOR i=1 TO 1000
  3717.        y%(i)=x|(i)^2
  3718.      NEXT i
  3719. First, create a table of squares :
  3720.      DIM square%(255)
  3721.      FOR i=0 TO 255
  3722.        square%(i)=i*i
  3723.      NEXT i
  3724. Then use this table in the loop :
  3725.      FOR i=1 TO 1000
  3726.        y%(i)=square%(x|(i))
  3727.      NEXT i
  3728.  
  3729.  
  3730. FOR ... NEXT
  3731.  
  3732. I use local variables in Procedures if possible. But if you intend to 
  3733. compile the program later, you should declare the counter in a FOR ... 
  3734. NEXT loop as a global variable. In the compiled program, the loop will be 
  3735. executed faster!
  3736.  
  3737. If you use floating point count-variables in a FOR ... NEXT loop (or any 
  3738. other loop), you could encounter unexpected problems :
  3739.      FOR i#=0.1 TO 0.9 STEP 0.1
  3740.        PRINT i#
  3741.      NEXT i#
  3742. You would expect 0.9 as the result of the last addition (0.8 + 0.1), but 
  3743. 0.9 is never printed! This is not a bug in GFA-Basic, but caused by the 
  3744. internal (binary) representation of floating point numbers. The last 
  3745. addition results in a number slightly larger than 0.9 and therefore the 
  3746. loop is left after printing 0.8 . If you insert the line
  3747.        i#=ROUND(i#,14)
  3748. in the loop, you can solve this problem. But the best solution is to avoid 
  3749. floating point count-variables in loops. Integer count-variables are much 
  3750. faster. You could easily change the loop to :
  3751.      FOR i=1 TO 9
  3752.        PRINT USING "#.#";i/10
  3753.      NEXT i
  3754. One more time: 'i' is a word-variable, because I use word-variables as 
  3755. the default for number-variables without postfix.
  3756.  
  3757. If you use a floating point variable in a REPEAT UNTIL loop, you can avoid 
  3758. the rounding error by using the special operator '==' :
  3759.      i#=0
  3760.      REPEAT
  3761.        i#=i#+0.1
  3762.        PRINT i#
  3763.      UNTIL i#==0.9
  3764. But you can't use the '=='-operator in a FOR ... NEXT loop.
  3765.  
  3766. In the following two examples a byte-variable is used as the counter :
  3767.      FOR i|=5 DOWNTO -1
  3768.        PRINT i|
  3769.      NEXT i|
  3770.      '     
  3771.      FOR i|=250 TO 256
  3772.        PRINT i|
  3773.      NEXT i|
  3774. Of course, a byte-variable cannot have a value of -1 or 256. GFA does not 
  3775. abort with an error-message, but skips the loops. Not a true bug perhaps, 
  3776. but close.
  3777.  
  3778.  
  3779. Loops
  3780.  
  3781. Although you can use many different loops in GFA-Basic 3.0, there are 
  3782. basically only two varieties. You can first test a condition, and then 
  3783. either continue or leave the loop. Or you can first enter the loop, and 
  3784. then test a condition to decide if you are going to continue or leave. 
  3785.  
  3786. In an interpreted program the first choice is the fast FOR ... NEXT loop, 
  3787. then the (slower) REPEAT ... UNTIL loop and finally the (slowest) WHILE 
  3788. ... WEND loop. In a compiled program all loops are executed equally fast! 
  3789. If you use a DO ... LOOP, an EXIT IF condition will always take some extra 
  3790. time.
  3791. Try to avoid a negative test in a loop, as this will take more time. E.g. 
  3792. replace :
  3793.      WHILE NOT condition!
  3794.        (...)
  3795.      WEND
  3796. by the much faster :
  3797.      DO UNTIL condition!
  3798.        (...)
  3799.      LOOP
  3800. Or similarly replace :
  3801.      REPEAT
  3802.        (...)
  3803.      UNTIL NOT condition!
  3804. by the faster :
  3805.      DO
  3806.        (...)
  3807.      LOOP WHILE condition!
  3808.  
  3809. Finally, you could combine the test of one condition at the start of the 
  3810. loop with the test of another condition at the end of the loop :
  3811.      DO UNTIL condition_1!
  3812.        (...)
  3813.      LOOP WHILE condition_2!
  3814.  
  3815.  
  3816.                            19.  PROGRAM CONTROL
  3817.  
  3818.  
  3819. GOSUB
  3820.  
  3821. A Procedure can be called in one of the following ways :
  3822.      GOSUB proc
  3823.      @proc
  3824.      proc
  3825. I prefer the second method, because this is spotted easily in a listing. 
  3826. Also, the same method can be used to call a function.
  3827.  
  3828.  
  3829. ON BREAK GOSUB
  3830.  
  3831. You can't stop a program if a recursively called function is executed (?).
  3832.  
  3833. Use ON BREAK CONT to prevent calling the Break-Procedure twice. Nobody can 
  3834. release the <Control> <Shift> <Alternate> keys fast enough :
  3835.      ON BREAK GOSUB break
  3836.      (...)
  3837.      PROCEDURE break
  3838.        ON BREAK CONT
  3839.        (...)
  3840.        ON BREAK GOSUB break
  3841.      RETURN
  3842. In this case the Break-Procedure is activated again before leaving the 
  3843. Procedure. Study the Standard Procedure Break (in one of the STANxxxx.LST-
  3844. files) for an example of this method.
  3845.  
  3846.  
  3847. ERROR
  3848.  
  3849. You can simulate ERRORs with values from -127 to 127. For GFA-errors use 
  3850. values from 0 to 93, for bomb-errors 102 (2 bombs) to 109 (9 bombs) and 
  3851. for TOS-errors -1 to -67.
  3852.  
  3853.  
  3854. EVERY and AFTER
  3855.  
  3856. It's not possible to use EVERY and AFTER at the same time. Both commands 
  3857. don't work during a long PAUSE or DELAY (or any other command that takes a 
  3858. lot of time). You can only call Procedures without parameters. Don't make 
  3859. the Procedure too long, or it may be called while being processed!
  3860.  
  3861. In a compiled program you have to incorporate '$I+ U+', or EVERY and AFTER 
  3862. can't be used.
  3863.  
  3864.  
  3865. GOTO
  3866.  
  3867. You can't use GOTO in a Procedure, a Function or a FOR ... NEXT loop.
  3868.  
  3869.  
  3870. DELAY
  3871.  
  3872. The DELAY-command does not operate correctly in version 3.07 of GFA-Basic. 
  3873. During DELAY a Break is impossible. A nastier bug is the appearance of the 
  3874. mouse-cursor during DELAY, even after HIDEM. You are advised to use PAUSE 
  3875. instead.
  3876.  
  3877.  
  3878. CHAIN
  3879.  
  3880. In GFA-Basic all variables and arrays are lost after CHAINing the next 
  3881. program. However, you could use the 160-byte buffer of the scrap-library 
  3882. to pass a short message to the next program :
  3883.      buffer$=SPACE$(160)           ! 160 bytes maximum ??
  3884.      message$="this message was sent by the previous program"
  3885.      message$=message$+CHR$(0)
  3886.      LSET buffer$=message$
  3887.      r%=SCRP_WRITE(buffer$)        ! r%=0 if error
  3888.      CHAIN file$
  3889. Read the message with :
  3890.      buffer$=SPACE$(160)
  3891.      r%=SCRP_READ(buffer$)
  3892.      message$=CHAR{V:buffer$}
  3893. The use of this buffer is completely illegal, but who cares if you don't 
  3894. use a scrap-library? Unfortunately the GFA-editor seems to think so too, 
  3895. so you should experiment a little before trusting this method.
  3896.  
  3897.  
  3898. EXEC
  3899.  
  3900. If you are going to run another program more than once, you'll have to use 
  3901. EXEC 3 :
  3902.      base%=EXEC(3,file$,"","")          ! load, but don't start yet
  3903.      base$=STR$(base%)
  3904.      cmdl$=CHR$(LEN(base$)+1)+base$     ! create command line
  3905.      (...)
  3906.      r%=EXEC(4,"",cmdl$,"")             ! now run it 
  3907. The variable r% contains a value returned by the program (or -39 if not 
  3908. enough memory was available). Repeat the last line if you want to run the 
  3909. loaded program again. Of course you should use EXEC 0 if you're going to 
  3910. run the program one time only. Read the paragraph 'RESERVE' if you are 
  3911. going to use EXEC 3.
  3912.  
  3913. If you call a '*.PRG'-program with EXEC 0, you pass the null-string ("") 
  3914. as the command-line. You need the command-line only if you call a '*.TTP'-
  3915. program. The command-line is converted to upper case and can't exceed 125 
  3916. bytes. The first byte of the command-line (usually) determines the length 
  3917. of the line, so the command-line can't contain more than 124 characters. 
  3918. You can use this in a TTP-program (compiled GFA-Basic program, extension 
  3919. changed to TTP), but it's easier to read the command-line with :
  3920.      cmdl$=CHAR{BASEPAGE+&H81}
  3921.  
  3922.  
  3923.                               20.  GRAPHICS
  3924.  
  3925.  
  3926. SETCOLOR and VSETCOLOR
  3927.  
  3928. With commands like COLOR, DEFTEXT, DEFFILL, etc., you use a VDI colour-
  3929. index. Unfortunately SETCOLOR uses a different table :
  3930.      VDI colour-index    : 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
  3931.      SETCOLOR (Low rez)  : 0 15  1  2  4  6  3  5  7  8  9 10 12 14 11 13
  3932.      SETCOLOR (Med rez)  : 0  3  1  2
  3933. From this table it follows you would have to use 'SETCOLOR 2,r,g,b' to 
  3934. change colour-index 3. By the way, all Line-A commands use the SETCOLOR-
  3935. table as well! This is not a "bug", but a consequence of two different 
  3936. colour-tables that are used by GEMDOS and GEM. You are advised to use :
  3937.      VSETCOLOR index,r,g,b
  3938. This index is exactly the same as the colour-index, so you would use 
  3939. 'VSETCOLOR 2,r,g,b' in order to change colour-index 2. If you like, you 
  3940. could use the hexadecimal 3-byte mix-value :
  3941.      VSETCOLOR index,&Hrgb
  3942. But you won't like it at all, because this doesn't work properly. GFA-
  3943. Basic swaps the r- and g-byte, so you would have to use :
  3944.      VSETCOLOR index,&Hbgr
  3945. Better avoid this method, or you'll experience colour-changes if GFA 
  3946. corrects this bug in a future version. 
  3947.  
  3948. In High resolution you can invert the screen-colours with :
  3949.      VSETCOLOR 0,0       ! reverse High-screen (black background)
  3950.      VSETCOLOR 1,0       ! normal High-screen (black letters)
  3951. An inverted screen is perhaps slightly less suitable for text, but 
  3952. graphics look superb.
  3953.  
  3954. Colour-index 0 determines the colour of the background in Low and Medium 
  3955. resolution. This index also determines the colour of the border on your 
  3956. screen. You can change this colour, although you can't draw or PRINT on 
  3957. the screen-border of your colour monitor. The colour of all PRINTed text 
  3958. is determined by colour-index 1, unless you use the 'Esc b' command (read 
  3959. the paragraph 'PRINT' again if your long-term memory is too short) :
  3960.      VSETCOLOR 0,r,g,b   ! change colour of background
  3961.      VSETCOLOR 1,r,g,b   ! change colour of all PRINTed text
  3962.  
  3963.  
  3964. Palette
  3965.  
  3966. Before changing colours, you should always save the current palette. And 
  3967. do restore the old palette before the user exits the program. I hate 
  3968. programs that return to a pink or yellow desktop. You can store the 
  3969. palette either in an integer array or in a string, using XBIOS 7 
  3970. (Setcolor) :
  3971.  
  3972.      PROCEDURE save.palette
  3973.        LOCAL i
  3974.        ERASE old.palette%()
  3975.        DIM old.palette%(15)
  3976.        FOR i=0 TO 15
  3977.          old.palette%(i)=XBIOS(7,i,-1)
  3978.        NEXT i
  3979.      RETURN
  3980.      '
  3981.      PROCEDURE make.palette.string(VAR pal$)
  3982.        LOCAL n
  3983.        pal$=""
  3984.        FOR n=0 TO 15
  3985.          pal$=pal$+MKI$(XBIOS(7,n,-1))
  3986.       NEXT n
  3987.      RETURN
  3988. The string-method is compatible with Degas. Restore the old palette with 
  3989. the corresponding Procedures :
  3990.      PROCEDURE restore.palette
  3991.        LOCAL i
  3992.        FOR i=0 TO 15
  3993.          VOID XBIOS(7,i,old.palette%(i))
  3994.        NEXT i
  3995.      RETURN
  3996.      '
  3997.      PROCEDURE change.palette(pal.string$)
  3998.        VOID XBIOS(6,L:VARPTR(pal.string$))
  3999.      RETURN
  4000. You could also use the Standard Procedure Standard.low.colors or 
  4001. Standard.med.colors to restore the default palette. You can find these 
  4002. Procedures in the STANxxxx.LST-files.
  4003.  
  4004. You can examine the rgb-value of a certain VDI colour-index with :
  4005.      PROCEDURE rgb.value(index,VAR rgb$)
  4006.        LOCAL col%
  4007.        col%=XBIOS(7,color.index(index),-1)
  4008.        rgb$=RIGHT$(HEX$(col%),3)
  4009.      RETURN
  4010. The Standard Array color.index() is used to convert the VDI colour-index.
  4011.  
  4012. A completely new palette for Medium resolution can be installed with :
  4013.      PROCEDURE new.med.colors
  4014.        LOCAL n,r,g,b,col$
  4015.        RESTORE med.new.col.data
  4016.        FOR n=0 TO 3
  4017.          READ col$
  4018.          r=VAL(LEFT$(col$))
  4019.          g=VAL(MID$(col$,2,1))
  4020.          b=VAL(RIGHT$(col$))
  4021.          VSETCOLOR n,r,g,b
  4022.        NEXT n
  4023.        med.new.col.data
  4024.        DATA 000,000,000,000
  4025.      RETURN
  4026. You can show the current palette on the screen with the Procedure 
  4027. Palette.box :
  4028.      PROCEDURE palette.box(x,y,h,w)
  4029.        ' *** left upper corner of rectangle at x,y
  4030.        ' *** rectangle-height h; width of one colour-box w
  4031.        LOCAL arect.fill,fill.adr%,i,x1,x2
  4032.        x2=x+16*w+2
  4033.        COLOR black
  4034.        BOX x,y,x2,y+h
  4035.        arect.fill=-1
  4036.        f%=V:arect.fill
  4037.        IF low.res!
  4038.          FOR i=0 TO 15
  4039.            x1=ADD(SUCC(x),MUL(i,w))
  4040.            ARECT x1,SUCC(y),ADD(x1,w),PRED(ADD(y,h)),color.index(i),0,f%,0
  4041.          NEXT i
  4042.        ELSE IF med.res!
  4043.          FOR i=0 TO 3
  4044.            x1=ADD(SUCC(x),MUL(i,w))
  4045.            ARECT x1,SUCC(y),ADD(x1,w),PRED(ADD(y,h)),color.index(i),0,f%,0
  4046.          NEXT i
  4047.        ENDIF
  4048.      RETURN
  4049.  
  4050. You can darken the screen by dimming all colours simultaneously with the 
  4051. Procedure Dim.colors :
  4052.      PROCEDURE dim.colors(reg1,reg2,val)
  4053.        ' *** dim colours from VDI colour-index reg1 to reg2 with val
  4054.        ' *** for val=1 colour 254 (rgb) will become 143
  4055.        LOCAL i,r,g,b
  4056.        FOR i=reg1 TO reg2
  4057.          @rgb.value(i,rgb$)
  4058.          r=MAX(PRED(VAL(LEFT$(rgb$))),0)
  4059.          g=MAX(PRED(VAL(MID$(rgb$,2,1))),0)
  4060.          b=MAX(PRED(VAL(RIGHT$(rgb$))),0)
  4061.          VSETCOLOR i,r,g,b
  4062.        NEXT i
  4063.      RETURN
  4064.  
  4065. Nothing is impossible in GFA-Basic, even colour-cycling is easy with 
  4066. EVERY in the Procedure Color.cycle :
  4067.      PROCEDURE color.cycle(reg1,reg2,time)
  4068.        ' *** cycles colours from VDI colour-index reg1 to reg2
  4069.        ' *** global :  COLOR.CYCLE!  COL.REG1  COL.REG2
  4070.        IF NOT color.cycle!
  4071.          col.reg1=reg1
  4072.          col.reg2=reg2
  4073.          color.cycle!=TRUE
  4074.          EVERY time GOSUB cycle.once
  4075.        ELSE
  4076.          color.cycle!=FALSE
  4077.          EVERY STOP
  4078.        ENDIF
  4079.      RETURN
  4080.      ' 
  4081.      PROCEDURE cycle.once
  4082.        LOCAL col1%,col2%
  4083.        col1%=XBIOS(7,color.index(col.reg2),-1)
  4084.        FOR reg=col.reg1 TO PRED(col.reg2)
  4085.          col2%=XBIOS(7,color.index(reg),-1)
  4086.          ~XBIOS(7,color.index(reg),col1%)
  4087.          SWAP col1%,col2%
  4088.        NEXT reg
  4089.        ~XBIOS(7,color.index(col.reg2),col1%)
  4090.      RETURN
  4091. Call the Procedure Color.cycle again to stop the colour-cycling.
  4092.  
  4093.  
  4094. DEFMARK
  4095.  
  4096. The point as mark-symbol (No. 1) cannot be enlarged. Other mark-symbols 
  4097. can be enlarged, but all lines in the symbol retain a width of one pixel. 
  4098. The size of a symbol must be a multiple of 11 plus 6: 0, 17, 28, 39, 50. 
  4099. For a value in between, the prior allowed size is chosen. Perhaps there is 
  4100. some magic hidden in the allowed sizes, or am I missing something?
  4101.  
  4102.  
  4103. DEFFILL
  4104.  
  4105. If you haven't defined your own Fill-pattern, the Atari-symbol will be 
  4106. used after DEFFILL 1,4,x. The desktop Fill-pattern is DEFFILL 1,2,4.
  4107.  
  4108. The Fill-pattern string can consist of 16, 32 or 64 words (MKI$-format). 
  4109. Word 1 to 16 is needed for bitplane 0 (High resolution), word 17 to 32 for 
  4110. bitplane 1 (Medium resolution) and word 33 to 64 for the bitplanes 2 and 3 
  4111. (Low resolution). In all resolutions, the pattern occupies a rectangle of 
  4112. 16x16 pixels on the screen. The same 16x16 rectangle is also used for the 
  4113. mouse-cursor and sprites. You can always use a Fill-pattern in a lower 
  4114. resolution, e.g. a High-pattern in Medium or Low resolution, but not the 
  4115. other way around. Examine the three Procedures Initio.high.fill1, 
  4116. Initio.med.fill1 and Initio.low.fill1 to see how easy you can design your 
  4117. own Fill-patterns. There's gold in them thar Fills. You could surprise the 
  4118. user with a bomb-pattern :
  4119.      PROCEDURE initio.bomb.fill
  4120.        ' *** global :  BOMB.FILL$
  4121.        RESTORE bomb.fill
  4122.        @make.high.fill(bomb.fill$)
  4123.        bomb.fill:
  4124.        DATA 0000011000000000
  4125.        DATA 0010100100000000
  4126.        DATA 0000000010000000
  4127.        DATA 0100100001000000
  4128.        DATA 0001000111110000
  4129.        DATA 0000000111110000
  4130.        DATA 0000011111111100
  4131.        DATA 0000111111111110
  4132.        DATA 0000110111111110
  4133.        DATA 0001111111111111
  4134.        DATA 0001111111101111
  4135.        DATA 0000111111101110
  4136.        DATA 0000111111011110
  4137.        DATA 0000011111111100
  4138.        DATA 0000001111111000
  4139.        DATA 0000000011100000
  4140.      RETURN
  4141.      ' 
  4142.      PROCEDURE make.high.fill(VAR fill$)
  4143.        LOCAL i,pat$,pat%
  4144.        CLR fill$
  4145.        FOR i=1 TO 16
  4146.          READ pat$
  4147.          pat%=VAL("&X"+pat$)
  4148.          fill$=fill$+MKI$(pat%)
  4149.        NEXT i
  4150.      RETURN
  4151.  
  4152. Be careful, a screen filled with this pattern might provoke a heart-
  4153. attack. If it doesn't, you could try the following dirty trick (High 
  4154. resolution only) with the Procedures Busy and Achtung :
  4155.      @busy          ! looks like the computer is very busy
  4156.      ~INP(2)        ! but nothing happens, until the user presses a key...
  4157.      @achtung
  4158.      PAUSE 500
  4159.      CLS
  4160.      PRINT " Thank you for your patience, I'm not busy anymore ..."
  4161.      PAUSE 150
  4162.  
  4163. Many Fill-patterns are available as files. You can use these with 
  4164. something like Procedure Initio.fill1 :
  4165.      PROCEDURE initio.fill1(VAR pattern$)
  4166.        LOCAL bytes
  4167.        bytes=32         ! 32 bytes for High resolution
  4168.        ' *** load Fill-pattern (32 bytes for High resolution) here
  4169.        INLINE fill1%,32
  4170.        pattern$=STRING$(bytes,0)
  4171.        BMOVE fill1%,V:pattern$,bytes
  4172.        DEFFILL ,pattern$
  4173.      RETURN
  4174.  
  4175. FILLing a screen with a pattern takes some time, especially in High 
  4176. resolution. Use the following method for almost immediate filling of the 
  4177. entire High resolution screen :
  4178.      PROCEDURE full.fill(fill%)
  4179.        ACLIP 1,0,0,639,399
  4180.        ARECT 0,0,639,399,1,0,fill%,15
  4181.        ACLIP 0,0,0,639,399
  4182.      RETURN
  4183. Fill% is the address of a FILL-pattern (32 bytes). This very fast 
  4184. alternative Fill-method works in High resolution only.
  4185.  
  4186.  
  4187. DEFLINE
  4188.  
  4189. After 'DEFLINE ,n' all horizontal lines have a width of n pixels (n should 
  4190. be odd), except in Medium resolution. But if n is larger than 1, all 
  4191. vertical lines are n+2 pixels wide! I have trouble counting the pixels 
  4192. in Medium resolution. I think the width of horizontal lines is :
  4193.          n :   1 3 5 7 9
  4194.      width :   1 1 3 3 5 etc.
  4195. Is this documented anywhere?
  4196.  
  4197. You define your own Line-patterns by using a negative 16-bit value (from  
  4198. -&X1 to -&X1111111111111111). Each set bit corresponds with a pixel in the 
  4199. Line-pattern (High resolution). The highest bit (15) corresponds with the 
  4200. leftmost pixel of the pattern. Don't get confused if the editor changes 
  4201. the negative binary number you entered as a pattern. The editor uses a 
  4202. special notation for negative binary numbers. 
  4203.  
  4204. GFA-Basic represents integer numbers as binary strings of 32 bits. The 
  4205. most significant bit (31) determines the sign of the integer. If this bit 
  4206. is 0, the remaining 31 bits represent an "ordinary" positive number. But 
  4207. if the most significant bit is 1, the remainder is a negative number in 
  4208. 'two's complement' notation. I won't try to explain that. In any case, the 
  4209. next time you type -&X111 and a friend is watching you, don't blink your 
  4210. eyes, but casually remark "of course the editor converts this into two's 
  4211. complement notation". That's also the reason GFA-Basic can work with 
  4212. integers from -(2^31) to +(2^31)-1. 
  4213.  
  4214.  
  4215. DEFTEXT
  4216.  
  4217. In some publications you can read about 'shadowed text' (style = 32), but 
  4218. unfortunately our GEM doesn't know this style. You can even find the mask 
  4219. for shadowed text with WORD{L~A+92}, but it's 0.
  4220.  
  4221. I never succeeded in finding the current text-style with VDISYS 38 
  4222. (vqt_attributes). Either a bug in GEM or my mistake. I don't want to know, 
  4223. because the easy way is :
  4224.      txt.style=WORD{L~A+90}
  4225. This could be important if you intend to use DEFTEXT in a Procedure, but 
  4226. would like to restore the original DEFTEXT-settings before leaving the 
  4227. Procedure.
  4228.  
  4229. With DEFTEXT you can set the height of TEXT-letters. A letter occupies 
  4230. more space though, determined by the letter-box :
  4231.  
  4232.      letter-height  letter-box     system-font
  4233.            4          6 x 6        icon
  4234.            6          8 x 8        Medium & Low rez
  4235.           13          8 x 16       High resolution
  4236.  
  4237. The letter-height is the distance from Descent-Line to Ascent-Line, but 
  4238. the Bottom-Line and Top-Line lie at least one pixel lower/higher. The 
  4239. height of the letter-box is the distance from Bottom-Line to Top-Line.
  4240.  
  4241. Most letters rest on the Base-Line, but letters with a descender (g,j,p, 
  4242. etc.) rest on the Descent-Line. If you are still with me, from top to 
  4243. bottom we have the following lines :
  4244.      Top-Line
  4245.      Ascent-Line
  4246.      Base-Line
  4247.      Descent-Line
  4248.      Bottom-Line
  4249. Drop me a line if you don't understand this.
  4250.  
  4251.  
  4252. GRAPHMODE
  4253.  
  4254. If you draw a rectangle with BOX in GRAPHMODE 3 (Xor-mode), the pixel in 
  4255. the left upper corner is not drawn. Actually this pixel is drawn twice, 
  4256. and in GRAPHMODE 3 this means the pixel disappears. Use PLOT to draw this 
  4257. pixel :
  4258.      GRAPHMODE 3
  4259.      BOX x1,y1,x2,y2
  4260.      PLOT x1,y1          ! and fill the gap
  4261.  
  4262. With PBOX in GRAPHMODE 3 you'll also get trouble in the same corner. Avoid 
  4263. this by using the command 'BOUNDARY 0' first :
  4264.      GRAPHMODE 3
  4265.      BOUNDARY 0 
  4266.      PBOX 50,50,100,100
  4267.  
  4268. GRAPHMODE 3 is especially useful if you make a temporary drawing. Draw the 
  4269. same picture a second time to restore the original screen. Examine Proce-
  4270. dures like Rubber.line, Draw.box and Drag.box for examples of this method. 
  4271. The Procedure Rubber.line is used to draw a line from (x,y) to the mouse-
  4272. cursor :
  4273.      PROCEDURE rubber.line(x,y,VAR x2,y2)
  4274.        LOCAL x1,y1,x2,y2,k
  4275.        GRAPHMODE 3
  4276.        DEFMOUSE 3
  4277.        SHOWM
  4278.        MOUSE x1,y1,k
  4279.        REPEAT                           ! main loop
  4280.          LINE x,y,x1,y1                 ! draw line
  4281.          REPEAT
  4282.            MOUSE x2,y2,k
  4283.          UNTIL x2<>x1 OR y2<>y1 OR k>0  ! mouse moved
  4284.          LINE x,y,x1,y1                 ! undraw line
  4285.          x1=x2
  4286.          y1=y2
  4287.        UNTIL k>0         ! mouse-click : ready (x2 and y2 returned)
  4288.        GRAPHMODE 1
  4289.        LINE x,y,x2,y2    ! this is it
  4290.        HIDEM
  4291.        DEFMOUSE 0
  4292.        PAUSE 10
  4293.      RETURN
  4294.  
  4295. You could also use the 'GRAPHMODE 3'-method for animation, but the XBIOS 5 
  4296. (Setscreen) method is more suitable.
  4297.  
  4298. Don't try to draw in GRAPHMODE 3 with a linewidth greater than 1 pixel. 
  4299. GEM will surprise you with some modern art if you can't resist the 
  4300. temptation.
  4301.  
  4302. If you want to confirm a particular choice of the user, you can invert the 
  4303. relevant part of the screen with the Procedure Invert.block. Call this 
  4304. Procedure again with the same parameters to restore the original screen : 
  4305.      PROCEDURE invert.block(x1,y1,x2,y2,color)
  4306.        GRAPHMODE 3
  4307.        DEFFILL color,1
  4308.        BOUNDARY 0
  4309.        PBOX x1,y1,x2,y2
  4310.        BOUNDARY 1
  4311.        GRAPHMODE 1
  4312.      RETURN
  4313.  
  4314. You can 'grey out' an unavailable option on the screen with :
  4315.      PROCEDURE block.dimmer(x1,y1,x2,y2,color)
  4316.        GRAPHMODE 3
  4317.        DEFFILL color,2,2
  4318.        BOUNDARY 0
  4319.        PBOX x1,y1,x2,y2
  4320.        BOUNDARY 1
  4321.        GRAPHMODE 1
  4322.      RETURN
  4323. Call this Procedure again to restore the screen.
  4324.  
  4325. The entire (High resolution) screen can be dimmed with :
  4326.      PROCEDURE screen.dimmer
  4327.        ' *** global :   DIMMER.SCREEN$   DIMMER.SWITCH!
  4328.        IF dimmer.switch!
  4329.          SPUT dimmer.screen$
  4330.          dimmer.switch!=FALSE
  4331.        ELSE
  4332.          SGET dimmer.screen$
  4333.          GRAPHMODE 4
  4334.          DEFFILL 1,2,4
  4335.          PBOX 0,0,639,399
  4336.          dimmer.switch!=TRUE
  4337.        ENDIF
  4338.      RETURN
  4339. The screen will be restored if you call the Procedure again.
  4340.  
  4341.  
  4342. PLOT and DRAW
  4343.  
  4344. You can use both 'PLOT x,y' and 'DRAW x,y' to set a point on the screen. 
  4345. The size of the point can be changed :
  4346.      DEFLINE ,size,2,2   ! change size of points
  4347. But the shapes you'll see don't look like points anymore, due to the same 
  4348. problem as described in the paragraph 'DEFLINE'. Use PCIRCLE for proper 
  4349. fat points.
  4350.  
  4351.  
  4352. PCIRCLE
  4353.  
  4354. With CLIP on, a PCIRCLE touching the upper screen-border is not filled 
  4355. properly in High resolution :
  4356.      CLIP 0,0,640,400
  4357.      PCIRCLE 0,0,50
  4358. I don't know if we should blame GFA or GEM for not filling the two top-
  4359. lines in the circle.
  4360.  
  4361.  
  4362. CURVE
  4363.  
  4364. With the command CURVE you can draw a Bezier-curve :
  4365.      CURVE x1,y1,x2,y2,x3,y3,x4,y4
  4366. The Bezier-curve starts at (x1,y1) and ends at (x4,y4). The other two 
  4367. points act like little magnets. You can also use this command to draw a 
  4368. 'normal' curve between two points by letting the points (x3,y3) and 
  4369. (x4,y4) coincide. Try the following to see what I mean :
  4370.      GRAPHMODE 3
  4371.      MOUSE x2,y2,k
  4372.      DO
  4373.        CURVE 10,100,x2,y2,110,100,110,100    ! draw curve
  4374.        REPEAT
  4375.          MOUSE x,y,k
  4376.        UNTIL x<>x2 OR y<>y2
  4377.        CURVE 10,100,x2,y2,110,100,110,100    ! erase curve
  4378.        x2=x
  4379.        y2=y
  4380.      LOOP
  4381. This method could be used to draw large letters.
  4382.  
  4383.  
  4384. TEXT
  4385.  
  4386. The coordinates used with TEXT determine the start of the Base-Line of the 
  4387. text. The descenders of letters like 'g', 'j', and 'p' lie below the Base-
  4388. Line. This is especially important, not to say frustrating, if you use 
  4389. TEXT with an angle of 90, 180 or 270 degrees. The text rotates anticlock-
  4390. wise around the TEXT-coordinates!
  4391.  
  4392. If you intend to combine PRINTed text with TEXT, you probably will like 
  4393. the Procedure Text.at as the analogue of 'PRINT AT' :
  4394.      PROCEDURE text.at(c,l,t$)
  4395.       TEXT (c-1)*char.width,l*char.height+3*high.res!+2*(NOT high.res!),t$
  4396.      RETURN
  4397.  
  4398. You can use TEXT to print "digital" numbers (ASCII-code 16-25) :
  4399.      FUNCTION digital$(number$)
  4400.        LOCAL dig$,i
  4401.        CLR dig$
  4402.        FOR i=1 TO LEN(number$)
  4403.          dig$=dig$+CHR$(BCLR(ASC(MID$(number$,i,1)),5))
  4404.        NEXT i
  4405.        RETURN dig$
  4406.      ENDFUNC
  4407. Use this Function as follows :
  4408.      TEXT x,y,@digital$("1237")
  4409.  
  4410.  
  4411. SPRITE
  4412.  
  4413. You could design and save sprites in vitro with one of the many Sprite-
  4414. editors that are available. Or you can use something like the Procedure 
  4415. Initio.sprite1 to create a sprite in vivo. Compare this Procedure also 
  4416. with the Procedure Initio.mouse1 :
  4417.      PROCEDURE initio.sprite1
  4418.        ' *** global :  SPRITE1$
  4419.        RESTORE pattern.sprite1
  4420.        @make.sprite(sprite1$)
  4421.        pattern.sprite1:
  4422.        ' *** x,y,mode(0=normal;1=XOR),mask-colour,sprite-colour
  4423.        DATA 0,0,0,0,1
  4424.        ' *** mask-pattern (1 = pixel on , 0 = pixel off)
  4425.        DATA 0000000000000000
  4426.        DATA 0000000000000000
  4427.        DATA 0000000000000000
  4428.        DATA 0000000000000000
  4429.        DATA 0000000000000000
  4430.        DATA 0000000000000000
  4431.        DATA 0000000000000000
  4432.        DATA 0000000000000000
  4433.        DATA 0000000000000000
  4434.        DATA 0000000000000000
  4435.        DATA 0000000000000000
  4436.        DATA 0000000000000000
  4437.        DATA 0000000000000000
  4438.        DATA 0000000000000000
  4439.        DATA 0000000000000000
  4440.        DATA 0000000000000000
  4441.        ' *** sprite-pattern
  4442.        DATA 0000000000000000
  4443.        DATA 0000000000000000
  4444.        DATA 0000000000000000
  4445.        DATA 0000000000000000
  4446.        DATA 0000000000000000
  4447.        DATA 0000000000000000
  4448.        DATA 0000000000000000
  4449.        DATA 0000000000000000
  4450.        DATA 0000000000000000
  4451.        DATA 0000000000000000
  4452.        DATA 0000000000000000
  4453.        DATA 0000000000000000
  4454.        DATA 0000000000000000
  4455.        DATA 0000000000000000
  4456.        DATA 0000000000000000
  4457.        DATA 0000000000000000
  4458.      RETURN
  4459.      ' 
  4460.      PROCEDURE make.sprite(VAR s$)
  4461.        LOCAL x,y,mode,msk.color,spr.color,n,msk%,spr%,msk.pat$,spr.pat$
  4462.        LOCAL msk$,spr$,pat$
  4463.        CLR msk.pat$,spr.pat$,pat$
  4464.        READ x,y,mode,msk.color,spr.color
  4465.        FOR n=1 TO 16
  4466.          READ msk$
  4467.          msk%=VAL("&X"+msk$)
  4468.          msk.pat$=msk.pat$+MKI$(msk%)
  4469.       NEXT n
  4470.        FOR n=1 TO 16
  4471.          READ spr$
  4472.          spr%=VAL("&X"+spr$)
  4473.          spr.pat$=spr.pat$+MKI$(spr%)
  4474.        NEXT n
  4475.        FOR n=1 TO 16
  4476.          pat$=pat$+MID$(msk.pat$,n*2-1,2)+MID$(spr.pat$,n*2-1,2)
  4477.        NEXT n
  4478.        s$=MKI$(x)+MKI$(y)+MKI$(mode)+MKI$(color.index(msk.color))
  4479.        s$=s$+MKI$(color.index(spr.color))+pat$
  4480.      RETURN
  4481. The mask should be an exact copy of the sprite-pattern if you need a 
  4482. transparant sprite. Leave the mask empty (all '0') and the sprite will 
  4483. disappear behind objects on the screen. Fill the mask with '1' and the 
  4484. 16x16 sprite will always remain visible. Switch mask- and sprite-colour in 
  4485. the first DATA-line to create a "reverse" sprite. Or use any VDI colour-
  4486. index that is available in the current resolution.
  4487.  
  4488. If you put a sprite on the screen, the background (16x16 pixels) is 
  4489. temporarily saved. Using more than one sprite simultaneously, it is 
  4490. essential you remove sprites in reverse order. This is necessary because a 
  4491. sprite could overlap another sprite. Removing the top sprite first ensures 
  4492. that the original background will reappear after removing the first 
  4493. sprite, e.g. :
  4494.  
  4495.      DO
  4496.        (...)
  4497.        SPRITE s2$        ! remove sprites...
  4498.        SPRITE s1$
  4499.        VSYNC             ! prevents blinking, but slows down
  4500.        SPRITE s1$,x1,y1  ! draw sprites...
  4501.        SPRITE s2$,x2,y2
  4502.        (...)
  4503.      LOOP
  4504.  
  4505.  
  4506. VQT_EXTENT
  4507.  
  4508. The function VQT_EXTENT can be used if you would like to draw a rectangle 
  4509. around a text-string :
  4510.      ~VQT_EXTENT(txt$,x1,y1,x2,y2,x3,y3,x4,y4)
  4511. The coordinates of the four corners depend on the angle of the text (0, 
  4512. 90, 180 or 270 degrees) and of course on the size of the text. The point 
  4513. (x1,y1) is the lower left corner of the imaginary rectangle around the 
  4514. text and the other points are arranged anticlockwise around the text-
  4515. string. Because the text rotates around the TEXT-coordinates (start of the 
  4516. Base-Line), it will take some trial and error to determine the correct 
  4517. position of the rectangle if the angle is not 0 degrees. In the following 
  4518. table you'll find the "true" origin of the rectangle, the width and the 
  4519. height of the rectangle, and also the actual position of the lower left 
  4520. corner of the text-block (x1,y1) :
  4521.      angle     position (x1,y1)    origin    width     height
  4522.         0         lower left        x1,y1     x2         y4
  4523.       900         lower right       x4,y4     x1         y3
  4524.      1800         upper right       x3,y3     x4         y2
  4525.      2700         upper left        x2,y2     x3         x4
  4526. The coordinates of the origin are (0,0), so with an angle of 0 degrees 
  4527. both x1 and y1 are 0. The rectangle rests on the x-axis, while the left 
  4528. side coincides with the y-axis. This is a "mathematical" y-axis, not a 
  4529. "screen" y-axis. This means you go upwards for positive y-values. For an 
  4530. angle of 0 degrees the coordinates will be :
  4531.      (x4,y4).           .(x3,y3)
  4532.             . TEXTBLOCK . 
  4533.      (x1,y1)             (x2,y2)
  4534.  
  4535. If you understand the table, you should be surprised by the height 'x4' 
  4536. instead of 'y1' at an angle of 270 degrees. I think I discovered a bug in 
  4537. GEM here. Correct GEM by changing the following variables if an angle of 
  4538. 270 degrees is used :
  4539.      y1=x4
  4540.      SWAP x4,y4
  4541. Now, the height is 'y1' as you suspected. Clever, aren't we? I have not 
  4542. been able to confirm my discovery. None of my reference-books mention the 
  4543. bug. 
  4544.  
  4545.  
  4546. Line-A
  4547.  
  4548. The Line-A commands are faster than the corresponding VDI-commands in GFA-
  4549. Basic. The difference should be even greater after loading GDOS (?). In 
  4550. the following table you can find how many times faster the Line-A command 
  4551. is :
  4552.       PSET / PLOT  = 3
  4553.       PTST / POINT = 2
  4554.      HLINE / LINE  = 2
  4555.      ARECT / PBOX  = 1.5
  4556. The syntax of Line-A commands is more complicated, but that's no problem 
  4557. for us GFA-experts. Line-A commands use the 'SETCOLOR-index', so you'll 
  4558. probably need the Standard Array color.index().
  4559.  
  4560. HLINE
  4561.  
  4562. An additional advantage of the commands HLINE, ARECT and APOLY is that you 
  4563. don't have to change the DEFFILL-parameters in the main program. For solid 
  4564. horizontal lines, use :
  4565.      pattern=-1
  4566.      adr%=V:pattern
  4567.      HLINE x1,y,x2,color,mode,adr%,0
  4568. You can't use &X1111111111111111 (16 bits) for the pattern, because bit 15 
  4569. of a word-variable is a flag for a negative number. Yes, that's why the 
  4570. largest positive word is 2^15 - 1 (32767). The solution to this little
  4571. problem is to assign -1 to the word-variable. You have my word, now all 16 
  4572. bits are 1. Use BIN$ if you don't believe me.
  4573.  
  4574. For very complicated patterns you could use a word-array :
  4575.      DIM pattern(i)
  4576.      adr%=V:pattern(0)
  4577.      (...)               ! put fill-pattern in pattern(0) to pattern(i)
  4578.      HLINE x1,y,x2,color,mode,adr%,i
  4579.  
  4580.  
  4581. ACHAR and ATEXT
  4582.  
  4583. It's difficult to combine the Line-A commands ACHAR and ATEXT with TEXT. 
  4584. The coordinates used with ACHAR and ATEXT determine the position of the 
  4585. left upper corner of the (first) letter-box. That's the Top-Line, not the 
  4586. Base-Line.
  4587.  
  4588. You can't use the text-style underlined (8) with ACHAR and ATEXT. Probably 
  4589. a GFA-bug.
  4590.  
  4591.  
  4592. GET and PUT
  4593.  
  4594. You could save a rectangular part of the screen as follows :
  4595.      GET x1,y1,x2,y2,pic$
  4596.      BSAVE file$,V:pic$,LEN(pic$)  ! use the extension PUT in the filename
  4597.  
  4598. Later, you could put the saved picture back on the screen with :
  4599.      OPEN "I",#1,file$
  4600.      LET bytes%=LOF(#1)            ! how many bytes needed?
  4601.      CLOSE #1
  4602.      picture$=SPACE$(bytes%)       ! reserve some space,
  4603.      BLOAD file$,V:picture$        ! load the picture
  4604.      PUT x,y,picture$              ! and look at it
  4605.  
  4606. The Procedures Message, Warning, Message.on and Message.off use GET and 
  4607. PUT to save and later restore the part of the screen that is used for 
  4608. text.
  4609.  
  4610. A GET-string starts with three words for width, height and number of 
  4611. bitplanes. The number of bitplanes is determined by the resolution: 1 for 
  4612. High, 2 for Medium and 4 for Low. After these three words follows the 
  4613. actual picture as a list of words. As the picture-width is not necessarily 
  4614. a multiple of 16, any bits beyond the right border will be ignored by the 
  4615. PUT-command. 
  4616.  
  4617. Here is the connection between GRAPHMODE and PUT-mode :
  4618.      GRAPHMODE      PUT-mode
  4619.          1             3 (default)
  4620.          2             7
  4621.          3             6
  4622.          4            13
  4623.  
  4624. I have encountered a few programs in GFA-Basic 2.0 where PUT was used 
  4625. just outside the screen. In GFA-Basic 3.0 the program didn't work. The 
  4626. same occurred in a program where a picture was BLOADed a few bytes before 
  4627. the screen-RAM. I don't understand why GFA-Basic 3.0 doesn't accept this, 
  4628. as there is some unused space there (read the paragraph 'RAM'), but I've 
  4629. learned to correct this when I convert a program from GFA-Basic 2.0 to 
  4630. version 3.0.
  4631.  
  4632.  
  4633. Degas-Pictures
  4634.  
  4635. A Degas picture-file contains not only the actual picture (same format as 
  4636. SGET-picture), but also the colour-palette. Use the Procedure Show.degas 
  4637. to load and show a Degas-picture :
  4638.      PROCEDURE show.degas(degas$)
  4639.        LOCAL degas.picture$,degas.picture%,degas.palette$
  4640.        LOCAL degas.palette%
  4641.          degas.picture$=SPACE$(32000)
  4642.          degas.picture%=VARPTR(degas.picture$)
  4643.          degas.palette$=SPACE$(32)
  4644.          degas.palette%=VARPTR(degas.palette$)
  4645.          OPEN "I",#90,degas$
  4646.          SEEK #90,2                            ! skip resolution
  4647.          BGET #90,degas.palette%,32            ! load palette of picture
  4648.          SEEK #90,34
  4649.          BGET #90,degas.picture%,32000         ! load actual picture
  4650.          CLOSE #90
  4651.          ~XBIOS(6,L:degas.palette%)            ! change palette
  4652.          SPUT degas.picture$                   ! show the picture
  4653.      RETURN
  4654.  
  4655. The original Degas-files have a length of 32034 bytes :
  4656.      1 word         - resolution
  4657.      16 words       - palette
  4658.      16000 words    - picture data
  4659. You can use BTST to check the resolution (bit 0 = Low, bit 1 = Medium, bit 
  4660. 2 = High), but you could also look at the extension of the filename 
  4661. (PI1/PI2/PI3 for Low/Medium/High). In the second Degas-version (Degas 
  4662. Elite), 16 words for "colour-animation" can be added after the picture 
  4663. data.
  4664. A Degas Elite picture can (and really should!) be saved in a compressed 
  4665. format. The extensions PC1/PC2/PC3 are used for Low/Medium/High 
  4666. resolution. Also, the highest bit of the resolution-word is set as a flag 
  4667. for a compressed picture. With the Procedure Show.comp.degas you can load 
  4668. and show a compressed Degas-picture.
  4669.  
  4670.  
  4671. Neochrome-Pictures
  4672.  
  4673. Sometimes the "Neochrome"-format is used for pictures (32128 bytes) :
  4674.      1 integer           - resolution (0/1/2 for Low/Medium/High)
  4675.      16 words            - palette
  4676.      12 bytes            - filename (nnnnnnnn.eee)
  4677.      4 bytes + 1 word    - colour animation data
  4678.      18 integers         - reserved
  4679.      16000 words         - picture data
  4680.  
  4681.  
  4682. VSYNC
  4683.  
  4684. The VSYNC-command is useful if you want to prevent irritating blinking 
  4685. during animation. Always VSYNC before drawing a new picture in an 
  4686. animation sequence (including SPRITE-animation). The program is slowed 
  4687. down of course, because it waits for a vertical blank interrupt before 
  4688. starting to draw. But it looks much nicer.
  4689.  
  4690.  
  4691. Scroll
  4692.  
  4693. With BMOVE and RC_COPY you can accomplish pretty smooth scrolling. GET/PUT 
  4694. is too slow, and only works on the logical screen. BITBLT is more 
  4695. flexible, but also more complicated. And not faster (?). Study the 
  4696. Procedures Scroll.up and Scroll.down to see how you could scroll the 
  4697. entire screen up or down :
  4698.  
  4699.      PROCEDURE scroll.up(scroll.lines,scroll.color)
  4700.        LOCAL n,bytes,move.bytes,source%
  4701.        IF high.res!
  4702.          LET bytes=80*scroll.lines
  4703.        ELSE
  4704.          LET bytes=160*scroll.lines
  4705.        ENDIF
  4706.        move.bytes=32000-bytes
  4707.        source%=physbase%+bytes
  4708.        VSYNC
  4709.        BMOVE source%,physbase%,move.bytes 
  4710.        DEFFILL scroll.color
  4711.        PBOX 0,scrn.y.max-scroll.lines+1,scrn.x.max,scrn.y.max 
  4712.        FOR n=1 TO DIV(scrn.y.max,scroll.lines)                
  4713.          VSYNC
  4714.          BMOVE source%,physbase%,move.bytes
  4715.        NEXT n
  4716.      RETURN
  4717. Can anybody explain the interference lines that sometimes appear during 
  4718. the scrolling?
  4719.  
  4720. Several fade-over effects can be found in the Procedures Up.scroll, 
  4721. Slider.scroll, etc. Most Procedures can only be used in High resolution.
  4722.  
  4723. For scrolling of one or more text-lines you could use the Procedures 
  4724. Scroll.text.up and Scroll.text.down :
  4725.      PROCEDURE scroll.text.up(begin,end)
  4726.        LOCAL screen%,sx,sy,w,h,dx,dy
  4727.        IF begin>1 AND end>=begin
  4728.          screen%=XBIOS(3)          ! logical screen
  4729.          sx=0
  4730.          sy=(begin-1)*char.height
  4731.          w=scrn.x.max
  4732.          h=(end-begin+1)*char.height
  4733.          dx=0
  4734.          dy=sy-char.height
  4735.          RC_COPY screen%,sx,sy,w,h TO screen%,dx,dy
  4736.        ELSE
  4737.          PRINT bel$;
  4738.        ENDIF
  4739.      RETURN
  4740. This method is also used in the Procedure Debug.
  4741.  
  4742.  
  4743. ACLIP
  4744.  
  4745. Line-A commands are 'CLIP-sensitive', so you should always use an appro-
  4746. priate ACLIP-command before a Line-A command. The following Line-A 
  4747. commands are not influenced by ACLIP : ALINE, HLINE, PSET, PTST and 
  4748. BITBLT.
  4749.  
  4750.  
  4751. Blitter
  4752.  
  4753. The Blitter-TOS (1987) allows you to switch the Blitter on/off. I couldn't 
  4754. test the following Procedure, because I don't have a Blitter. But if I 
  4755. understand the function XBIOS 64 (Blitmode) correctly, you could switch 
  4756. the Blitter on and off from GFA-Basic :
  4757.      PROCEDURE blitter(switch!)
  4758.        LOCAL status
  4759.        status=XBIOS(64,-1)
  4760.        IF BTST(status,1)           ! Blitter available?
  4761.          IF switch!
  4762.            status=BSET(status,0)   ! Blitter on
  4763.          ELSE
  4764.            status=BCLR(status,0)   ! Blitter off
  4765.          ENDIF
  4766.          ~XBIOS(64,status)         ! do it
  4767.        ENDIF
  4768.      RETURN
  4769.  
  4770. By the way, Line A commands do not use the Blitter. The Blitter-chip 
  4771. contains a hardware-routine that replaces the Line A BitBlt-function 
  4772. (BITBLT in GFA-Basic). All Mega ST's have a Blitter installed.
  4773.  
  4774.  
  4775.                                21.  EVENTS
  4776.  
  4777.  
  4778. MENU()
  4779.  
  4780. There is no easy way to test in a program if an accessory has been 
  4781. selected by the user. MENU(1) looks promising, but the value 40 (select 
  4782. accessory) or 41 (close accessory) is only sent to the accessory! It 
  4783. would have been nice to be able to determine if an accessory has been 
  4784. closed, because GEM will clear the accessory-window and will fill the 
  4785. space with the desktop-pattern. No easy solution for this one, sorry. The 
  4786. best idea probably is to test frequently with 'IF MENU(1)=20' if a redraw 
  4787. is necessary, e.g. :
  4788.      ON MENU MESSAGE GOSUB redraw
  4789.      (...)
  4790.      PROCEDURE redraw
  4791.        IF MENU(1)=20
  4792.          (...)           ! redraw screen
  4793.        ENDIF
  4794.      RETURN
  4795. This method only works if you have opened a window.
  4796.  
  4797.  
  4798. ON MENU BUTTON
  4799.  
  4800. The syntax for ON MENU BUTTON is :
  4801.      ON MENU BUTTON clicks,button,event GOSUB proc
  4802. For both 'button' and 'event' you can use the numbers 0-3. The variable 
  4803. 'clicks' stands for the maximal number of clicks you want to register. If 
  4804. you choose '2', the Procedure will be called if the user clicks once or 
  4805. twice : 
  4806.      ON MENU BUTTON 2,1,1 GOSUB proc
  4807. It's not possible to wait for a double-click, unless the progam is really 
  4808. waiting, and not doing anything else :
  4809.      SELECT EVNT_BUTTON(2,1,1)
  4810.      CASE 1
  4811.        ' clicked once
  4812.      CASE 2
  4813.        ' clicked twice
  4814.      ENDSELECT
  4815. But you can't combine this with an ON MENU loop.
  4816.  
  4817. If you use the described method :
  4818.      ON MENU BUTTON 2,1,1 GOSUB proc
  4819. you could use MENU(15) in the called Procedure to check if the user 
  4820. clicked twice. The same Procedure would be called after a single click, 
  4821. but you could ignore that. Fasten your seatbelts now. If you run such a 
  4822. program the first time, a double click is not registered in MENU(15). If 
  4823. you suspect a bug and run the program again, MENU(15) works all right. 
  4824. Nasty.
  4825.  
  4826. Another bug, but this time a GEM-bug (I think), after :
  4827.      ON MENU BUTTON 1,2,2 GOSUB proc
  4828. The Procedure is called immediately, whether the right mouse-button was 
  4829. pressed or not. 
  4830.  
  4831. If you want to switch ON MENU BUTTON temporarily off, use :
  4832.      ON MENU BUTTON clicks,button,event GOSUB dummy
  4833. The Procedure Dummy should be empty. Use the same method to switch other 
  4834. ON MENU commands temporarily off.
  4835.  
  4836.  
  4837. ON MENU IBOX
  4838.  
  4839. You can define two independent rectangles with ON MENU IBOX and/or ON MENU 
  4840. OBOX, either :
  4841.      - one IBOX and one OBOX
  4842.      - two IBOXes
  4843.      - two OBOXes
  4844.  
  4845.  
  4846.                             22.  PULLDOWN MENU
  4847.  
  4848.  
  4849. OPENW 0
  4850.  
  4851. Even if you don't need a window, you could 'OPENW 0' if you use a 
  4852. pulldown menu. The top line (y-coordinates 0 to 18 in High resolution, 
  4853. that's where your menu is) is now protected against accidental drawing. 
  4854. After 'OPENW 0' 19 is always added to the y-coordinate, so with 'PLOT 0,0' 
  4855. the point is actually drawn at (0,19).
  4856.  
  4857.  
  4858. Desk-submenu
  4859.  
  4860. The first submenu in a pulldown menu should be the Desk-submenu ('Desk'), 
  4861. usually with the following lay-out :
  4862.      Info
  4863.      ------------
  4864.      Accessory 1
  4865.      Accessory 2
  4866.      (...)
  4867. If the user chooses the Info-item, you should show some information about 
  4868. the program. The AES takes care of the accessory-items, you simply use 
  4869. '1,2,3,4,5,6' in the corresponding DATA-line. If you use '-,-,-,-,-,-' the 
  4870. user won't be able to choose an accessory from your program, but all 
  4871. loaded accessories still occupy memory.
  4872.  
  4873.  
  4874. File-submenu
  4875.  
  4876. Most pulldown-menu's contain a File-submenu ('File') as the second 
  4877. submenu. The following lay-out is more or less standard :
  4878.      New file       ^N
  4879.      Open file ...  ^O
  4880.      -----------------
  4881.      Close          ^C
  4882.      Save           ^S
  4883.      Save as ...    ^M
  4884.      Abort          ^A
  4885.      -----------------
  4886.      Quit           ^Q
  4887. With '...' you announce that further input from the user will be 
  4888. requested. If at all possible, you should offer optional keyboard-
  4889. alternatives for the experienced user. With '^N' you remind the user of 
  4890. the <Control> <N> alternative. The character with ASCII-code 7 is used as 
  4891. the symbol for <Alternate>. By general agreement, the Quit-choice always 
  4892. is the last item of the File-submenu.
  4893.  
  4894. By the way, never leave the last (rightmost) submenu without options, e.g. 
  4895. during development of a program. There must be at least one option in the 
  4896. last submenu, or it's reset-time again.
  4897.  
  4898.  
  4899.                                23.  WINDOWS
  4900.  
  4901.  
  4902. GFA-windows
  4903.  
  4904. You'll notice that this chapter is rather short. This reflects my 
  4905. reservations about the use of windows. I know very few programs that use 
  4906. windows sensibly. For these programs GEM-windows indeed are a blessing. 
  4907. But most programs are better off without windows. GEM just slows the 
  4908. screen-output down. Cover your TOS-screen with windows only if you really 
  4909. need them.
  4910.  
  4911. GFA-Basic has four "easy" windows for not too complicated jobs. Draw an 
  4912. imaginary cross on the screen. The intersection of the two lines is 
  4913. determined by the coordinates in 'OPENW n,x,y'. If you show more than one 
  4914. window on the screen, you should realize that resizing one window auto-
  4915. matically changes the size of the other three windows as well (remember 
  4916. the cross?). Use the AES window-commands if you need independent windows.
  4917.  
  4918. The four GFA-windows reserve the top line for a pulldown menu. If you use 
  4919. your own AES-windows, you should protect the top line yourself, e.g. with 
  4920. 'OPENW 0'.
  4921.  
  4922. A standard-method for the use of GFA-windows looks like this :
  4923.      TITLEW #1," title "      ! automatically centered
  4924.      INFOW #1,"information"   ! left justified
  4925.      OPENW 1                  ! or use FULLW #1
  4926.      CLEARW 1
  4927.      (...)
  4928.      CLOSEW 1
  4929.      CLOSEW 0
  4930. I don't know how to use '#' properly. The editor does not accept '#' in 
  4931. 'OPEN #1', you have to use 'OPENW 1'. If you use FULLW instead of OPENW, 
  4932. you have to use 'FULLW #1'. In this case the '#' has to be used, or the 
  4933. command doesn't work at all! The GFA-editor always inserts a '#' after 
  4934. TITLEW and INFOW, even if you didn't type one. What the # is going on?
  4935.  
  4936.  
  4937. CLOSEW
  4938.  
  4939. If you have opened a window in your program, always use 'CLOSEW 0' before 
  4940. returning to the editor. If you don't, you can't work normally in Direct 
  4941. Mode. If you did forget, you can type 'CLOSEW 0' in Direct Mode and 
  4942. everything works fine again.
  4943.  
  4944. If you use the AES window-commands, always call WIND_CLOSE(handle) before 
  4945. WIND_DELETE(handle).
  4946.  
  4947.  
  4948. TITLEW
  4949.  
  4950. You can clear a title with :
  4951.      TITLEW #n," "
  4952. Don't use "" instead of " ", or you won't be able to move the window 
  4953. afterwards!
  4954.  
  4955.  
  4956. CLEARW
  4957.  
  4958. After 'CLEARW #n' all visible areas of the window are cleared, without 
  4959. activating the window. GFA uses WIND_UPDATE and WIND_GET for this command. 
  4960. 'CLEARW n' both clears and activates the window.
  4961.  
  4962.  
  4963.                              24.  AES-LIBRARY
  4964.  
  4965.  
  4966. ALERT
  4967.  
  4968. If you need an empty line in an Alert-box, use :
  4969.      ALERT,3,"...| |...",1,"...",k
  4970. Note the space between the two vertical rules.
  4971.  
  4972. GFA-Basic allows 4 lines of 30 characters (High/Medium rez) if you use 
  4973. ALERT, but with FORM_ALERT you can use 5 lines. In both cases you can use 
  4974. not more than 3 buttons, each at most 8 characters (High/Medium rez) wide:
  4975.      m$=" line 1 | line 2 | line 3 | line 4 "
  4976.      ALERT 3,m$,1," OK ",k
  4977.      '
  4978.      m$="[3][ line 1 | line 2 | line 3 | line 4 | line 5 ][ OK ]"
  4979.      k=FORM_ALERT(1,m$)
  4980.  
  4981. In Low resolution you can use only half the number of characters you use 
  4982. in High/Medium resolution.
  4983.  
  4984. If some characters are not visible in a button, try broadening the Alert-
  4985. box by adding spaces to the widest text-line.
  4986.  
  4987. If you have pressed the left mouse-button on the very spot where an Alert-
  4988. button is about to appear, something goes wrong. GEM appears to remember 
  4989. your last mouse-click, and erroneously assumes you pressed the button 
  4990. after the Alert-box appeared. GEM only selects the button if the mouse-
  4991. click occurred in the exact area of the Alert-button. To avoid this 
  4992. problem you should make sure the user has released the mouse-button before 
  4993. you call the Alert-box :
  4994.      REPEAT
  4995.      UNTIL MOUSEK=0      ! wait until mouse released
  4996.  
  4997. By the way, the AES uses an 8K buffer to save the part of the screen where 
  4998. the Alert-box appears. Ditto for a menu.
  4999.  
  5000.  
  5001. SHEL_GET and SHEL_PUT
  5002.  
  5003. GFA-Basic is run from a 'Shell-Program', usually the Desktop. In that case 
  5004. the file DESKTOP.INF can be found in the Environment-Buffer. You can 
  5005. examine this file by transferring it to a string :
  5006.      d$=STRING$(1024,0)
  5007.      r%=SHEL_GET(1024,d$)
  5008. PRINTing this string is much easier than using a disk-editor to examine 
  5009. DESKTOP.INF. 
  5010.  
  5011. After changing the string, you could put it back in the buffer with :
  5012.      r%=SHEL_PUT(1024,d$)
  5013. This way you could change the lay-out of the desktop. If you change the 
  5014. string, you should know that the Desktop recognizes the end of DESKTOP.INF 
  5015. by the byte &H1A. So don't forget to put CHR$(26) at the end. If you want 
  5016. to save the new buffer, try :
  5017.      OPEN "O",#1,"\DESKTOP.INF"
  5018.      PRINT #1,LEFT$(d$,INSTR(d$,CHR$(26)))
  5019.      CLOSE #1
  5020.  
  5021.  
  5022.  
  5023.  
  5024.  
  5025.  
  5026. Is that all there is to tell about the AES-library? Certainly not, so at 
  5027. this point you will probably be bitterly disappointed. I avoid the AES-
  5028. Library whenever I can. Anyway, this is a subject that is thoroughly 
  5029. covered in most books about GFA-Basic 3.0. Everyone is entitled to his own 
  5030. opinion about the usefulness of RSC-files and other exotic subjects. 
  5031. Better still, write this chapter yourself. And the same to you too!
  5032.  
  5033.  
  5034.                            25.  GFAXPERT-FILES
  5035.  
  5036.  
  5037. Take your time to read this chapter carefully, before using the GFAXPERT-
  5038. Procedures or programs. The paragraph 'STANxxxx.LST' is essential reading. 
  5039. Don't forget to read the 'small print' in the last paragraph.
  5040.  
  5041.  
  5042. GFAXPERT.DOC
  5043.  
  5044. You're reading it. 
  5045.  
  5046.  
  5047. GFAXPERT.LIB
  5048.  
  5049. This folder (in GFAXPRT2.ARC for downloaders) contains a large collection 
  5050. of Procedures in several LST-files. Each LST-file contains one or more 
  5051. folded Procedures. Most Procedures are also listed in this text, or are at 
  5052. least mentioned. I suggest you Llist all the LST-files with unfolded 
  5053. Procedures for easy reference. You could also Llist all LST-files again 
  5054. with folded Procedures, so you will be able to locate a Procedure quickly.
  5055.  
  5056. Always read the comment-lines (' ***) in a Procedure before using it. You 
  5057. will find there if other Procedures are used, or Standard Globals (see 
  5058. paragraph 'STANxxxx.LST'). Sometimes a Procedure returns a global 
  5059. variable. Most variables are declared as LOCAL. And do read the relevant 
  5060. chapter of this text before using a Procedure.
  5061.  
  5062. GFA has released a library of graphics- and sound-routines. I am curious 
  5063. about the quality of these routines, but I certainly do not intend to pay 
  5064. DM 148.- for the library. My advice would be to use the library 
  5065. GFAXPERT.LIB and pay DM 148.- to me.
  5066.  
  5067.  
  5068. INLINE
  5069.  
  5070. The INLINE-folder (in GFAXPRT2.ARC for downloaders) contains INLINE-files 
  5071. that you will have to load after Merging certain Procedures. This is 
  5072. clearly indicated in such Procedures.
  5073.  
  5074.  
  5075. STANxxxx.LST
  5076.  
  5077. Before writing a program, I decide in which resolution the program will 
  5078. run. Then I Merge the corresponding STANxxx.LST-file (in the folder 
  5079. GFAXPERT.LIB) and use that as the standard framework for my program :
  5080.      STANHIGH.LST   - High resolution
  5081.      STANMED.LST    - Medium resolution
  5082.      STANLOW.LST    - Low resolution
  5083.      STANHIME.LST   - High or Medium resolution
  5084.      STANALL.LST    - all resolutions
  5085. After deleting the first two lines and entering the name of the program 
  5086. (e.g. TEST.GFA), I Save the program as AAPROG.GFA in the Procedure-
  5087. library. In this folder I have a few LST-files ready for easy Merging of 
  5088. Procedures into the program (AABLOCK1.LST, AABLOCK2.LST, etc.).
  5089.  
  5090. Before you continue, you should Llist the five STANxxxx.LST-files. Merge 
  5091. STANHIGH.LST, unfold all Procedures, then Llist. In the other files you 
  5092. could restrict unfolding to the Procedure Initio (and perhaps the 
  5093. Procedures xxx.mode and Standard.xxx.colors). I'll wait until you have the 
  5094. listings of the STAN-files in front of you...
  5095.  
  5096. Right, first I'll discuss STANHIGH.LST thoroughly. Later I'll point out 
  5097. some important features in the other STAN-files. You will not become an 
  5098. expert in structured programming immediately, but using the STAN-files 
  5099. should help.
  5100.  
  5101. (1) The first line ('STANHIGH.LST') is there to remind you how to 'Save,A' 
  5102. this file after you have changed it. Delete it if you are going to develop 
  5103. a new program.
  5104.  
  5105. (2) Enter the name of your new program (e.g. TEST.GFA) and immediately 
  5106. save the program as AAPROG.GFA in the Procedure-library.
  5107.  
  5108. (3) Word-variables are defined as the default.
  5109.  
  5110. (4) The Procedure Initio is called. In this Procedure the current 
  5111. resolution is checked, and after that, a few important global variables 
  5112. are defined (Standard Globals). The following Standard Globals are defined 
  5113. (read the comments in the listing for more information) :
  5114.      high.res!           scrn.col.max        return$
  5115.                          scrn.lin.max        esc$
  5116.      default.path$                           help$
  5117.                          white               undo$
  5118.      physbase%           black               
  5119.      logbase%                                interpreter$
  5120.                          on!                 run.only$
  5121.      scrn.x.max          off!                start.gfa$
  5122.      scrn.y.max                              start.prg$
  5123.                          bel$                
  5124.      char.width                              
  5125.      char.height                             
  5126. Also, the Standard Array color.index() is created, although you'll only 
  5127. need it for a few Procedures (e.g. Initio.sprite1).
  5128.  
  5129. (5) The Procedure Title.screen is not activated yet. You'll probably want 
  5130. to change that Procedure.
  5131.  
  5132. (6) A normal <Break> should be possible while developing a program. In the 
  5133. finished program you could activate the Procedure Break, or delete it. Be 
  5134. very careful with <Break> if the program uses RESERVE or has changed the 
  5135. address of the physical/logical screen.
  5136.  
  5137. (7) The main program usually is not much more than a list of Procedure-
  5138. calls, e.g. :
  5139.      @start.game
  5140.      @play.game
  5141.      @score
  5142. (8) Try to leave the program by calling the Procedure Exit. During 
  5143. development it's more convenient to leave with 'EDIT'.
  5144.  
  5145. (9) Two Standard Functions are defined: Center$ for centering text and 
  5146. Rev$ for PRINTing reverse. The last function uses VT52-codes, so use it on 
  5147. the TOS-screen only.
  5148.  
  5149. (10) The Standard Procedure High.mode (called from Initio) checks the 
  5150. current resolution and aborts with an appropriate message if the program 
  5151. is run in the wrong resolution.
  5152.  
  5153. (11) The Standard Procedure Get.path (called from Initio) returns the 
  5154. current path. Using the interpreter, GEMDOS returns the path of the 
  5155. interpreter (e.g. 'A:\'), not of the running program! That's why I use 
  5156. CHDRIVE + CHDIR in the shell-programs. In that case the Standard Global 
  5157. default.path$ does contain the path of the running GFA-program. If you 
  5158. develop the program, you should use CHDRIVE/CHDIR in Direct Mode if 
  5159. necessary. I am not happy with this method, but I know no other solution 
  5160. for GFA-programs. If I don't use this method, I always define the path in 
  5161. the Initiation-part, e.g. :
  5162.      path$="A:\GAMES\"        ! where are the data-files?
  5163. Now another GFA-user only has to change the path and the program can find 
  5164. the necessary files. For owners of the Run-Only interpreter you should 
  5165. describe the proper configuration in a READ.ME-file. With compiled GFA-
  5166. programs there is no problem, because GEMDOS will return the path of the 
  5167. running program.
  5168.  
  5169. (12) I like to begin every program with a title-screen. Change the 
  5170. Standard Procedure Title.screen, or delete it if you don't like title-
  5171. screens in your programs.
  5172.  
  5173. (13) The Standard Procedure Return is used by Title.screen.
  5174.  
  5175. (14) The Standard Procedure Break can be deleted if you don't need it. 
  5176. Don't use 'ON BREAK CONT' in your program, unless you have a very good 
  5177. reason to do so. Note that I have made it possible to use <Break> the 
  5178. normal way if the user chooses <CONT> while pressing the <Break>-
  5179. combination.
  5180.  
  5181. (15) The Standard Procedure Exit should always be used. This Procedure 
  5182. tries to go back to one of the shell-programs. If that's impossible, the 
  5183. Procedure decides to end with 'EDIT' or 'SYSTEM'. Is it possible to test 
  5184. in a program if it is run by the interpreter or if it is a compiled 
  5185. program? If the answer is yes, this Procedure could be improved.
  5186.  
  5187. (16) Other Procedures can be inserted after '*** Procedures ***'. Merge 
  5188. Procedures from the library GFAXPERT.LIB (or your own library) here. I use 
  5189. the following method :
  5190.      - New, so memory is clear
  5191.      - Merge relevant LST-file from library
  5192.      - choose (folded) Procedure and Write as block to AABLOCKx.LST
  5193.      - repeat previous steps for other Procedure(s)
  5194.      - Load AAPROG.GFA 
  5195.      - Merge AABLOCKx.LST at appropriate position(s)
  5196.      - Save program (press <Return> in Fileselector)
  5197. Of course, you'll have to write a few Procedures from scratch. Before you 
  5198. know it, you'll have reached The End. It's so easy to write a program in 
  5199. GFA-Basic 3.0, that I actually enjoy programming.
  5200.  
  5201. (17) Debugging is perhaps less fun than programming. Merge the Procedure 
  5202. Debug temporarily in your program if you need some help. And do save your 
  5203. program regularly! Fall back to the program AAPROG.BAK if your latest 
  5204. improvements were fatal. If you are completely satisfied, save the program 
  5205. under its proper name (TEST.GFA). Also save a back-up on another disk, 
  5206. just in case something terrible should happen to your original program.
  5207.  
  5208. (18) In STANALL.LST you'll notice in the Procedure Initio that I always 
  5209. start with the default palette (Procedures Standard.med.colors and 
  5210. Standard.low.colors). New Standard Globals in STANALL.LST are :
  5211.      red            med.res!
  5212.      green          low.res!
  5213. The Standard Array color.index() is very important in Medium or Low 
  5214. resolution.
  5215.  
  5216. (19) In STANHIME.LST (my favourite) the only important difference is the 
  5217. Procedure High.med.mode, where the current resolution is checked.
  5218.  
  5219. (20) In STANLOW.LST all 16 default-colours are now defined as Standard 
  5220. Globals :
  5221.      white          blue           grey           l.purple
  5222.      black          d.blue         l.black        d.purple
  5223.      red            brown          l.blue         d.yellow
  5224.      green          d.green        bluegreen      l.yellow
  5225. With two new Standard Functions you can change the colour of PRINTed text 
  5226. (Ink$) or the colour of the background (Paper$). Both functions work on 
  5227. the TOS-screen only. The current resolution is checked in the Procedure 
  5228. Low.mode.
  5229.  
  5230. (21) Nothing new in STANMED.LST, except the Procedure Med.mode to check 
  5231. the resolution.
  5232.  
  5233. Perhaps you find all this talk about a "standard" program-structure very 
  5234. boring. If you write a program, why care about structure? Because it's 
  5235. much easier to change a structured program, especially if you didn't write 
  5236. the program yourself. Change an unstructured program, and you're going to 
  5237. be surprised by some (hidden) unwanted side-effects. Make other users 
  5238. happy, spread your beautiful programs only if they are structured and well 
  5239. commented. Do spread the (listable) source of your program, so other users 
  5240. can learn from you. And don't be insulted if others improve your program. 
  5241. I certainly will not be insulted if you send me your own thoughts about 
  5242. structured programming in GFA-Basic 3.0. 
  5243.  
  5244.  
  5245.  
  5246. START
  5247.  
  5248. In the START-folder (in GFAXPRT2.ARC for downloaders) you will find the 
  5249. following programs :
  5250.      START.GFA      - High or Medium resolution
  5251.      STARTLOW.GFA   - Low resolution
  5252.      GFASTART.GFA   - all resolutions
  5253.  
  5254. I use two different disks for my GFA-programs. One for programs that run 
  5255. in High and/or Medium resolution (save the desktop in Medium resolution!). 
  5256. And one for programs that run in Low resolution.
  5257.  
  5258. START.GFA and STARTLOW.GFA are used as a kind of shell to run the GFA-
  5259. programs on these disks. Not a true shell, but it "feels" like all GFA-
  5260. programs are run from START.GFA and STARTLOW.GFA. I start a GFA-session 
  5261. by double-clicking the shell-program on the desktop ('GFA' has been 
  5262. installed as application for GFABASIC.PRG).
  5263.  
  5264. All my programs try to CHAIN one of the shell-programs when the user exits 
  5265. the program. Two important remarks if you decide to use these shell-
  5266. programs :
  5267.      - vertical frequency is switched to 60 Hz in Medium or Low resolu-
  5268.        tion; not a good idea if you use a TV through a modulator!
  5269.      - Write Verify Test is switched off
  5270. If you like, you can activate the check for a boot-virus in the shell-
  5271. programs. The shell-program and GFABASIC.PRG (or GFABASRO.PRG) should be 
  5272. in the main directory!
  5273.  
  5274. GFASTART.PRG is used in the same way with compiled GFA-programs. All my 
  5275. compiled GFA-programs try to CHAIN this shell-program when exiting. The 
  5276. source for this program is GFASTART.GFA. Compile this as GFASTART.PRG and 
  5277. put it in the main directory.
  5278.  
  5279. All three START-programs contain plenty comments, so you should be able to 
  5280. understand how the programs work by studying the listings. The shell-
  5281. programs certainly can be improved, I'm not yet satisfied with the current 
  5282. programs. 
  5283.  
  5284.  
  5285. small print
  5286.  
  5287. Read this paragraph carefully, before using the GFAXPERT-files. The files 
  5288. are not Public Domain!
  5289.  
  5290. You are free to use and change all GFAXPERT-files, but only for personal 
  5291. use. Certainly not for commercial use.
  5292.  
  5293. You are invited to copy the original GFAXPERT-disk or the GFAXPRTx.ARC-
  5294. files and give these to your friends. But you are not allowed to change 
  5295. anything on the disk or in the files. If you feel the urge to change 
  5296. something, don't do it, but write to me (read the chapter 'EPILOGUE').
  5297.  
  5298. You are not allowed to sell (files from) the GFAXPERT-disk or one of the 
  5299. GFAXPRTx.ARC-files. The disk GFAXPERT may only be sold by so-called Public 
  5300. Domain Clubs if they have my written permission to do so. BBS's are free 
  5301. to make the original GFAXPRTx.ARC-files available for downloading.
  5302.  
  5303. Any part from the text GFAXPERT.DOC or the Procedure-library GFAXPERT.LIB 
  5304. may be quoted in newsletters or magazines, if accompanied by a reference 
  5305. like :
  5306.       from GFAXPERT (2nd ed.) by Han Kempen
  5307.  
  5308. I cannot be held responsible for any damage that may result from running a 
  5309. GFAXPERT-program, using a Procedure from the library GFAXPERT.LIB, or 
  5310. using information from this text.
  5311.  
  5312.  
  5313. (c) Han Kempen, 3 July 1990
  5314.  
  5315.  
  5316.                                  EPILOGUE
  5317.  
  5318.  
  5319. Well, that's all folks. I'm quite certain there are still a few bugs to be 
  5320. found in this text and in the Procedure-Library GFAXPERT.LIB. By now you 
  5321. should have become an expert in GFA-Basic 3.0, so you will be able to spot 
  5322. them bugs immediately. Please let me know if you find one.
  5323.  
  5324. Perhaps you still have some unanswered questions about GFA-Basic. Or an 
  5325. answer to one of my own questions in this text. Or some neat Procedures. 
  5326. Or a brilliant program. I would appreciate it very much if you would send 
  5327. your letter and/or disk to :
  5328.  
  5329.      Han Kempen
  5330.      Rubensstraat 12
  5331.      7741 AR Coevorden
  5332.      the Netherlands
  5333.  
  5334. Do share your ideas, Procedures and programs with others, starting with 
  5335. me. Consider it a small payment for the GFAXPERT-files. Thanks.
  5336.  
  5337.  
  5338.  
  5339.  
  5340.  
  5341.  
  5342. Wishing you many happy hours with GFA-Basic 3.0,
  5343.  
  5344.  
  5345. Han Kempen
  5346.  
  5347.  
  5348.                                   INDEX
  5349.  
  5350.  
  5351.  
  5352.                        (#) = Procedure or Function
  5353.  
  5354.  
  5355. \ .....................................  29
  5356. " .....................................  41
  5357. 1st Word Plus .........................  62
  5358. 40-folder limit .......................  66
  5359.  
  5360. abbreviated commands ..................  12
  5361. accessory .............................  25,101
  5362. ACHAR .................................  96
  5363. ACLIP .................................  99
  5364. After$ (#) ............................  32
  5365. AFTER .................................  82
  5366. ALERT ................................. 106
  5367. application ...........................   9
  5368. ARECT .................................  88
  5369. ASCII-code ............................  33,34,36,37
  5370. Ascii.qsort (#) .......................  27
  5371. ATEXT .................................  96
  5372. attribute .............................  53
  5373. AUTO ..................................   9
  5374.  
  5375. BCHG ..................................  30
  5376. BCLR ..................................  29
  5377. Before$ (#) ...........................  32
  5378. Bezier-curve ..........................  92
  5379. BGET ..................................  62
  5380. BIOS  4 (Rwabs) .......................  59
  5381. BIOS  7 (Getbpb) ......................  56,60
  5382. BIOS  9 (Mediach) .....................  60
  5383. BIOS 10 (Drvmap) ......................  51
  5384. BIOS 11 (Kbshift) .....................  36
  5385. bit-mask ..............................  29
  5386. Blitter (#) ...........................  99
  5387. BLOAD .................................  61
  5388. Block.dimmer (#) ......................  91
  5389. Boolean ...............................  17
  5390. boot ..................................   9,61
  5391. BPB ...................................  56
  5392. BPUT ..................................  62
  5393. break .................................  10
  5394. Break (#) ............................. 110
  5395. BSAVE .................................  61
  5396. BSET ..................................  30,79
  5397. bug (GFA) .............................  12,20,24,25,31,32,36,42,80,83,
  5398.                                                         84,92,96,97,101
  5399. bug (TOS) .............................  25,35,55,56,63,64,66,70,95,102
  5400.  
  5401. calculations ..........................  79
  5402. Caps (#) ..............................  39
  5403. CapsLock ..............................  38
  5404. CARD ..................................  31
  5405. CHAIN .................................  83
  5406. Change.font (#) .......................  44
  5407. Change.midi.buffer (#) ................  67
  5408. Change.palette (#) ....................  85
  5409. characters ............................  16,34
  5410. CHDIR .................................  51,110
  5411. CLEAR .................................  19
  5412. CLEARW ................................ 105
  5413. CLIP ..................................  92
  5414. CLOSEW ................................ 104
  5415. cluster ...............................  58
  5416. Coldstart (#) .........................   9
  5417. color .................................  40
  5418. Color.cycle (#) .......................  86
  5419. correlation ...........................  31
  5420. COSQ ..................................  30
  5421. CURVE .................................  92
  5422. Cut and Paste .........................  13
  5423. Cycle.once (#) ........................  87
  5424.  
  5425. DATE$ .................................  22
  5426. Day.of.week (#) .......................  22
  5427. Debug (#) .............................  19,111
  5428. DEFFILL ...............................  87
  5429. DEFLINE ...............................  89
  5430. DEFLIST ...............................  15
  5431. DEFMARK ...............................  87
  5432. DEFMOUSE ..............................  72
  5433. DEFTEXT ...............................  89
  5434. DEFWRD ................................  17
  5435. Degas-Pictures ........................  97
  5436. Degas.screendump (#) ..................  46
  5437. DELAY .................................  83
  5438. Desk-submenu .......................... 103
  5439. DESKTOP.INF ........................... 106
  5440. DFREE .................................  56,58
  5441. Digital$ (#) ..........................  93
  5442. DIM ...................................  19
  5443. Dim.colors (#) ........................  86
  5444. DIR$() ................................  50
  5445. DIR ...................................  51
  5446. Direct mode ...........................  15
  5447. disk format ...........................  55
  5448. disk-swap .............................  60
  5449. Do.sound (#) ..........................  76
  5450. DRAW ..................................  91
  5451. DTA-buffer ............................  52
  5452. DUMP ..................................  19
  5453.  
  5454. Editor ................................  71
  5455. EQV ...................................  31
  5456. ERASE .................................  19,24
  5457. ERROR .................................  82
  5458. EVERY .................................  82
  5459. EXEC ..................................  24,83
  5460. EXIST .................................  54
  5461. Exit (#) .............................. 110
  5462.  
  5463. fade-over .............................  99
  5464. Fastprint (#) .........................  41
  5465. FAT ...................................  58
  5466. FDC ...................................  55
  5467. FGETDTA ...............................  52
  5468. File Allocation Table .................  58
  5469. File.copy (#) .........................  55
  5470. File-submenu .......................... 103
  5471. FILES .................................  51
  5472. FILESELECT ............................  63
  5473. Fileselect (#) ........................  64
  5474. Fileselector ..........................  63,71
  5475. floating point ........................  18
  5476. Floppy Write Test .....................  50
  5477. Folded Procedures .....................  13
  5478. font ..................................  43,89
  5479. Font.8x16 (#) .........................  43
  5480. Font.8x8 (#) ..........................  43
  5481. FONTKIT ...............................  44
  5482. FOR ... NEXT ..........................  79
  5483. Force.mediach (#) .....................  60
  5484. FORM_ALERT ............................ 106
  5485. FSETDTA ...............................  52
  5486. FSFIRST ...............................  52
  5487. FSNEXT ................................  52
  5488. Full.fill (#) .........................  88
  5489. FULLW ................................. 104
  5490. FUNCTION ..............................  19
  5491.  
  5492. GEMDOS 17 (Cprnos) ....................  45
  5493. GEMDOS 25 (Dgetdrv) ...................  50
  5494. GEMDOS 48 (Sversion) ..................  10
  5495. GEMDOS 54 (Dfree) .....................  56
  5496. GEMDOS 67 (Fattrb) ....................  53
  5497. GET ...................................  96
  5498. Get.path (#) .......................... 110
  5499. GFA-windows ........................... 104
  5500. GFAXPERT.DOC ..........................   7,108
  5501. GFAXPERT.LIB ..........................   7,108
  5502. GOSUB .................................  82
  5503. GOTO ..................................  82
  5504. GRAPHMODE .............................  90
  5505.  
  5506. HARDCOPY ..............................  45
  5507. harddisk ..............................  51,55,58,59
  5508. High.screendump.epson (#) .............  45
  5509. High.screendump.star24 (#) ............  45
  5510. HLINE .................................  96
  5511.  
  5512. IBOX .................................. 102
  5513. IF ... ENDIF ..........................  78
  5514. INFOW ................................. 194
  5515. Initio (#) ............................ 109
  5516. Initio.fill1 (#) ......................  88
  5517. Initio.high.fill1 (#) .................  87
  5518. Initio.keyget (#) .....................  36
  5519. Initio.logical.screen (#) .............  42
  5520. Initio.mouse1 (#) .....................  72
  5521. Initio.printer (#) ....................  47
  5522. Initio.sound (#) ......................  75
  5523. Initio.sprite1 (#) ....................  93
  5524. Initio.text.array (#) .................  62
  5525. Ink$ (#) ..............................  40
  5526. INKEY$ ................................  33
  5527. INLINE ................................  24,108
  5528. INP ...................................  62,67,70
  5529. INPAUX$ ...............................  70
  5530. INPMID$ ...............................  67
  5531. INPUT .................................  34,62
  5532. INPUT$ ................................  35
  5533. Insert-mode ...........................  15
  5534. INSTR .................................  32
  5535. INT{} .................................  23
  5536. integer ...............................  18
  5537. Intel.word (#) ........................  31
  5538. interleave ............................  57
  5539. Invert.block (#) ......................  91
  5540.  
  5541. joystick ..............................  74
  5542.  
  5543. Key.click (#) .........................  38
  5544. Key.repeat (#) ........................  39
  5545. keyboard ..............................  37
  5546. keyboard-buffer .......................  33
  5547. Keyboard.version (#) ..................  37
  5548. KEYDEF ................................  37
  5549. KEYGET ................................  35
  5550. KEYLOOK ...............................  36
  5551. KEYPAD ................................  37
  5552. KEYPRESS ..............................  37
  5553. KEYTEST ...............................  35
  5554. KILL ..................................  54
  5555.  
  5556. Line-A ................................  95
  5557. LINE INPUT ............................  35,62
  5558. Llist .................................  14
  5559. Load ..................................  13
  5560. LOCATE ................................  41
  5561. LOF ...................................  54
  5562. LOG ...................................  30
  5563. logical screen ........................  42
  5564. loops .................................  80,119
  5565. LSET ..................................  32
  5566.  
  5567. Make.high.fill (#) ....................  88
  5568. Make.mouse (#) ........................  73
  5569. Make.palette.string (#) ...............  85
  5570. Make.sprite (#) .......................  94
  5571. MALLOC ................................  25
  5572. MAX ...................................  31,78
  5573. Max.array (#) .........................  31
  5574. memory ................................  23,24,25
  5575. MENU() ................................ 101
  5576. Midi-buffer ...........................  67
  5577. Midi-commands .........................  67
  5578. Midi.monitor (#) ......................  68
  5579. MIN ...................................  78
  5580. MOD ...................................  29
  5581. monitor ...............................  10
  5582. MOUSE .................................  71
  5583. MS-DOS disk ...........................  58
  5584.  
  5585. NAME ..................................  54
  5586. Neochrome-Pictures ....................  98
  5587. New.med.colors (#) ....................  85
  5588. Normal.font (#) .......................  44
  5589. NOT ...................................  81
  5590.  
  5591. OBOX .................................. 102
  5592. ON BREAK GOSUB ........................  82
  5593. ON MENU BUTTON ........................ 101
  5594. ON MENU IBOX .......................... 102 
  5595. OPENW ................................. 104
  5596. OPENW 0 ............................... 103
  5597. Operating System ......................  10
  5598. OUT ...................................  40,62
  5599. Overwrite-mode ........................  15
  5600.  
  5601. palette ...............................  84,111
  5602. Palette.box (#) .......................  86
  5603. Paper$ (#) ............................  40
  5604. Parse.filename (#) ....................  65
  5605. parser ................................  32
  5606. PCIRCLE ...............................  92
  5607. physical screen .......................  42
  5608. Play.midi (#) .........................  68
  5609. PLOT ..................................  91
  5610. point-commands ........................  14
  5611. PRED ..................................  29
  5612. PRINT .................................  40
  5613. Print.stopwatch (#) ...................  21
  5614. PRINT TAB .............................  42
  5615. printer-commands ......................  47
  5616. printer-driver ........................  14
  5617. printer-parameters ....................  45
  5618. Printer.ready (#) .....................  45
  5619. PUT ...................................  96
  5620.  
  5621. QSORT .................................  26
  5622.  
  5623. RAM ...................................  23
  5624. RAM-disk ..............................  50
  5625. READ ..................................  20
  5626. RECALL ................................  62
  5627. Record.midi (#) .......................  67
  5628. RESERVE ...............................  23
  5629. reset .................................   9,50
  5630. RESTORE ...............................  20
  5631. Restore.palette (#) ...................  85
  5632. Restore.physical.screen (#) ...........  43
  5633. Return (#) ............................ 110
  5634. reverse ...............................  41,84
  5635. Rgb.value (#) .........................  85
  5636. right justification ...................  32
  5637. RS232-buffer ..........................  70
  5638. RSET ..................................  32
  5639. Rubber.line (#) .......................  90
  5640.  
  5641. samples ...............................  76
  5642. Save ..................................  14
  5643. Save,A ................................  14
  5644. Save.palette (#) ......................  85
  5645. scan-code .............................  33,36,37,38
  5646. scrap-library .........................  83
  5647. Screen.dimmer (#) .....................  91
  5648. Screendump (#) ........................  45
  5649. Scroll.text.up (#) ....................  99
  5650. Scroll.up (#) .........................  98
  5651. sectors ...............................  59
  5652. SELECT ................................  78
  5653. serial number .........................  57
  5654. SETCOLOR ..............................  84
  5655. SETMOUSE ..............................  71
  5656. SHEL_GET .............................. 106
  5657. SHEL_PUT .............................. 106
  5658. shell-program ......................... 112
  5659. SHL ...................................  79
  5660. Show.degas (#) ........................  97
  5661. Show.text.page (#) ....................  63
  5662. Shuffle (#) ...........................  20
  5663. SINQ ..................................  30
  5664. SOUND .................................  75
  5665. Soundmachine ..........................  77
  5666. special characters ....................  16
  5667. speech ................................  77
  5668. SPRITE ................................  93
  5669. SSORT .................................  26
  5670. Standard ..............................   7
  5671. Standard Array ........................ 109,111
  5672. Standard Functions .................... 110,111
  5673. Standard Globals ...................... 109,111
  5674. STANxxxx.LST .......................... 108
  5675. START ................................. 112
  5676. start-up ..............................   9
  5677. Step Rate .............................  50
  5678. STICK .................................  74
  5679. Stopwatch (#) .........................  21
  5680. STORE .................................  62
  5681. STRIG .................................  74
  5682. String.index.qsort (#) ................  28
  5683. SUCC ..................................  29
  5684. supervisor mode .......................  23
  5685. SWAP ..................................  20,31
  5686. Swap.screen (#) .......................  43
  5687. syntax ................................  12
  5688. system-font ...........................  43,89
  5689.  
  5690. Tab ...................................  13,41
  5691. TAB ...................................  42
  5692. TEXT ..................................  92
  5693. text-array ............................  62
  5694. Text.at (#) ...........................  92
  5695. TIME$ .................................  21
  5696. Time (#) ..............................  21
  5697. TIMER .................................  21
  5698. Title.screen (#) ...................... 110
  5699. TITLEW ................................ 104,105
  5700. TOS ...................................  10
  5701. TOS-screen ............................  40
  5702. TOUCH .................................  54
  5703. twisted format ........................  57
  5704. TYPE ..................................  20
  5705.  
  5706. VAR ...................................  18
  5707. variable type .........................  17
  5708. VDISYS 38 (vqt_attributes) ............  89
  5709. VQT_EXTENT ............................  95
  5710. VSETCOLOR .............................  84
  5711. VSYNC .................................  98
  5712. VT52 ..................................  40
  5713.  
  5714. Warmstart (#) .........................   9
  5715. WAVE ..................................  75
  5716. WIND_CLOSE ............................ 104
  5717. word ..................................  17,31 
  5718. WORD ..................................  23,59
  5719. write-protect .........................  60
  5720.  
  5721. XBIOS  0 (Initmous) ...................  71
  5722. XBIOS  5 (Setscreen) ..................  42
  5723. XBIOS  6 (Setpalette) .................  85,97
  5724. XBIOS  7 (Setcolor) ...................  84
  5725. XBIOS  8 (Floprd) .....................  60
  5726. XBIOS 10 (Flopfmt) ....................  56
  5727. XBIOS 15 (Rsconf) .....................  70
  5728. XBIOS 16 (Keytbl) .....................  37,38
  5729. XBIOS 18 (Protobt) ....................  57
  5730. XBIOS 19 (Flopver) ....................  56
  5731. XBIOS 32 (Dosound) ....................  75
  5732. XBIOS 33 (Setprt) .....................  45
  5733. XBIOS 36 (Prtblk) .....................  47
  5734. XBIOS 64 (Blitmode) ...................  99
  5735.  
  5736.